{"id":332,"date":"2026-06-28T14:48:56","date_gmt":"2026-06-28T14:48:56","guid":{"rendered":"https:\/\/chill-lab.eu\/?page_id=332"},"modified":"2026-07-05T10:20:26","modified_gmt":"2026-07-05T10:20:26","slug":"chill-barometer","status":"publish","type":"page","link":"https:\/\/chill-lab.eu\/it\/chill-barometer\/","title":{"rendered":"CHILL Barometer"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"332\" class=\"elementor elementor-332\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-81af258 e-flex e-con-boxed e-con e-parent\" data-id=\"81af258\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-24ae47e elementor-widget elementor-widget-html\" data-id=\"24ae47e\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<div id=\"chill-barometer-app\" class=\"chill-page chill-barometer chill-theme-barometer\">\n  <section class=\"chill-hero cb-hero\">\n    <div class=\"cb-hero-copy\">\n      <p class=\"chill-kicker\">CHILL Barometer<\/p>\n\n      <h1 class=\"chill-title\">\n        CHILL Barometer\n        <span class=\"chill-subtitle\">Measuring chilling pressure<\/span>\n      <\/h1>\n\n      <p class=\"chill-lead\">\n        Explore the intensity of chilling pressure across thematic areas, countries,\n        geographic areas, and rights involved.\n      <\/p>\n    <\/div>\n\n    <div class=\"cb-hero-badge\">\n      <span>Interactive<\/span>\n      <strong>Atlas-based assessment<\/strong>\n    <\/div>\n  <\/section>\n\n  <div id=\"cb-loading\" class=\"cb-loading\">Loading CHILL Atlas records\u2026<\/div>\n\n  <div class=\"cb-shell\" hidden>\n    <section class=\"cb-controls\" aria-label=\"CHILL Barometer filters\">\n      <div class=\"cb-search-wrap\">\n        <label class=\"cb-filter-label\" for=\"cb-search\">Search<\/label>\n        <input id=\"cb-search\" class=\"cb-search\" type=\"search\" placeholder=\"Title, country, theme, right\u2026\" \/>\n      <\/div>\n\n      <div id=\"cb-filter-panels\" class=\"cb-filter-grid\"><\/div>\n\n      <button type=\"button\" class=\"cb-reset\" id=\"cb-reset\">Reset<\/button>\n    <\/section>\n\n    <main class=\"cb-main\">\n      <section class=\"cb-kpis\" id=\"cb-kpis\"><\/section>\n\n      <section class=\"cb-card cb-score-card\">\n        <div class=\"cb-gauge-wrap\">\n          <div class=\"cb-gauge\" id=\"cb-gauge\">\n            <div class=\"cb-gauge-inner\">\n              <span id=\"cb-gauge-score\">0<\/span>\n              <small>\/100<\/small>\n            <\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"cb-score-text\">\n          <p class=\"cb-eyebrow\">Average intensity<\/p>\n          <h3 id=\"cb-score-title\">No data selected<\/h3>\n          <p id=\"cb-score-description\">\n            The score aggregates the filtered records. For restrictive measures, it indicates chilling pressure.\n            For protective measures, it indicates corrective or preventive impact.\n          <\/p>\n          <div class=\"cb-effect-strip\" id=\"cb-effect-strip\"><\/div>\n        <\/div>\n      <\/section>\n\n      <section class=\"cb-grid-two\">\n        <section class=\"cb-card\">\n          <div class=\"cb-section-head\">\n            <div>\n              <p class=\"cb-eyebrow\">Distribution<\/p>\n              <h3>Chilling effect level<\/h3>\n            <\/div>\n          <\/div>\n          <div id=\"cb-level-distribution\" class=\"cb-levels\"><\/div>\n        <\/section>\n\n        <section class=\"cb-card cb-mini-insight\">\n          <div>\n            <p class=\"cb-eyebrow\">Reading guide<\/p>\n            <h3>How to read the score<\/h3>\n            <p>\n              The direction of the effect matters: the same numerical score may indicate either chilling pressure or\n              protective impact, depending on the selected record type.\n            <\/p>\n          <\/div>\n\n          <div class=\"cb-legend\">\n            <span><i class=\"pressure\"><\/i>Pressure<\/span>\n            <span><i class=\"protective\"><\/i>Protective<\/span>\n            <span><i class=\"mixed\"><\/i>Mixed<\/span>\n          <\/div>\n        <\/section>\n      <\/section>\n\n      <section class=\"cb-card\">\n        <div class=\"cb-section-head cb-section-head-responsive\">\n          <div>\n            <p class=\"cb-eyebrow\">Aggregated view<\/p>\n            <h3 id=\"cb-group-title\">By thematic area<\/h3>\n          <\/div>\n\n          <div class=\"cb-tabs\" role=\"tablist\">\n            <button type=\"button\" class=\"cb-tab active\" data-group=\"thematic_area\">Thematic area<\/button>\n            <button type=\"button\" class=\"cb-tab\" data-group=\"country\">Country<\/button>\n            <button type=\"button\" class=\"cb-tab\" data-group=\"geographic_area\">Geographic area<\/button>\n            <button type=\"button\" class=\"cb-tab\" data-group=\"righst_involved\">Rights<\/button>\n          <\/div>\n        <\/div>\n\n        <div id=\"cb-group-chart\" class=\"cb-bars\"><\/div>\n      <\/section>\n\n      <section class=\"cb-card\">\n        <div class=\"cb-section-head\">\n          <div>\n            <p class=\"cb-eyebrow\">Filtered records<\/p>\n            <h3 id=\"cb-results-title\">Records<\/h3>\n          <\/div>\n        <\/div>\n        <div id=\"cb-results\" class=\"cb-results\"><\/div>\n      <\/section>\n    <\/main>\n  <\/div>\n<\/div>\n\n<style>\n  .chill-barometer {\n    max-width: 1180px;\n    background: var(--chill-bg);\n    color: var(--chill-text);\n    font-family: var(--chill-body-font);\n  }\n\n  .cb-hero {\n    display: grid;\n    grid-template-columns: minmax(0, 1fr) auto;\n    align-items: end;\n    gap: 24px;\n    margin-bottom: 18px;\n    background:\n      radial-gradient(circle at 8% 0%, rgba(56, 189, 248, 0.20), transparent 34%),\n      radial-gradient(circle at 100% 100%, rgba(125, 211, 252, 0.12), transparent 38%),\n      linear-gradient(135deg, #07111f 0%, #102542 52%, #0b1422 100%);\n  }\n\n  .cb-hero-badge {\n    position: relative;\n    z-index: 1;\n    min-width: 220px;\n    padding: 18px;\n    border: 1px solid var(--chill-border);\n    border-radius: 22px;\n    background: rgba(8, 19, 34, 0.72);\n    backdrop-filter: blur(14px);\n  }\n\n  .cb-hero-badge span,\n  .cb-hero-badge strong {\n    display: block;\n  }\n\n  .cb-hero-badge span {\n    margin-bottom: 6px;\n    color: var(--chill-barometer);\n    font-size: 12px;\n    font-weight: 900;\n    letter-spacing: 0.12em;\n    text-transform: uppercase;\n  }\n\n  .cb-hero-badge strong {\n    color: var(--chill-text);\n    font-size: 16px;\n    line-height: 1.25;\n  }\n\n  .cb-loading {\n    margin-top: 18px;\n    padding: 20px;\n    border: 1px solid var(--chill-border);\n    border-radius: var(--chill-radius-lg);\n    background: var(--chill-panel);\n    color: var(--chill-muted);\n  }\n\n  .cb-shell,\n  .cb-main {\n    display: grid;\n    gap: 18px;\n  }\n\n  .cb-controls {\n    position: sticky;\n    top: 14px;\n    z-index: 30;\n    display: grid;\n    grid-template-columns: minmax(220px, 1.2fr) minmax(0, 4fr) auto;\n    align-items: end;\n    gap: 12px;\n    padding: 14px;\n    border: 1px solid var(--chill-border);\n    border-radius: var(--chill-radius-xl);\n    background: rgba(11, 20, 34, 0.90);\n    backdrop-filter: blur(18px);\n    box-shadow: 0 18px 50px rgba(0, 0, 0, 0.24);\n  }\n\n  .cb-filter-grid {\n    display: grid;\n    grid-template-columns: repeat(6, minmax(0, 1fr));\n    gap: 10px;\n  }\n\n  .cb-search-wrap,\n  .cb-select {\n    min-width: 0;\n  }\n\n  .cb-filter-label {\n    display: block;\n    margin: 0 0 7px;\n    color: var(--chill-muted-2);\n    font-size: 11px;\n    font-weight: 850;\n    letter-spacing: 0.11em;\n    text-transform: uppercase;\n  }\n\n  .cb-search,\n  .cb-select-button,\n  .cb-reset {\n    width: 100%;\n    min-height: 48px;\n    border: 1px solid var(--chill-border);\n    border-radius: 15px;\n    outline: none;\n    background: rgba(16, 31, 51, 0.96);\n    color: var(--chill-text);\n    font: inherit;\n  }\n\n  .cb-search {\n    padding: 0 15px;\n  }\n\n  .cb-search::placeholder {\n    color: rgba(244, 247, 250, 0.42);\n  }\n\n  .cb-select {\n    position: relative;\n  }\n\n  .cb-select-button {\n    display: grid;\n    grid-template-columns: 1fr auto;\n    align-items: center;\n    gap: 8px;\n    padding: 8px 12px;\n    cursor: pointer;\n    text-align: left;\n    transition: border-color 0.2s ease, background 0.2s ease;\n  }\n\n  .cb-select-button:hover,\n  .cb-select.open .cb-select-button {\n    border-color: rgba(56, 189, 248, 0.44);\n    background: rgba(21, 44, 71, 0.96);\n  }\n\n  .cb-select-button strong {\n    display: block;\n    overflow: hidden;\n    color: var(--chill-text);\n    font-size: 13px;\n    line-height: 1.2;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n  }\n\n  .cb-select-button small {\n    color: var(--chill-muted-2);\n    font-size: 10px;\n    font-weight: 850;\n    letter-spacing: 0.08em;\n    text-transform: uppercase;\n  }\n\n  .cb-caret {\n    width: 9px;\n    height: 9px;\n    border-right: 2px solid var(--chill-muted);\n    border-bottom: 2px solid var(--chill-muted);\n    transform: rotate(45deg) translateY(-2px);\n    transition: transform 0.2s ease;\n  }\n\n  .cb-select.open .cb-caret {\n    transform: rotate(225deg) translateY(-2px);\n  }\n\n  .cb-menu {\n    position: absolute;\n    top: calc(100% + 9px);\n    left: 0;\n    right: 0;\n    z-index: 60;\n    display: none;\n    min-width: 260px;\n    max-height: 320px;\n    overflow: hidden;\n    border: 1px solid rgba(56, 189, 248, 0.28);\n    border-radius: 18px;\n    background: #091828;\n    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.45);\n  }\n\n  .cb-select.open .cb-menu {\n    display: block;\n  }\n\n  .cb-menu-scroll {\n    max-height: 260px;\n    overflow: auto;\n    padding: 8px;\n  }\n\n  .cb-option {\n    display: grid;\n    grid-template-columns: auto 1fr;\n    gap: 9px;\n    align-items: start;\n    padding: 9px;\n    border-radius: 12px;\n    cursor: pointer;\n    color: var(--chill-muted);\n    font-size: 13px;\n    line-height: 1.3;\n  }\n\n  .cb-option:hover {\n    background: rgba(255, 255, 255, 0.06);\n    color: var(--chill-text);\n  }\n\n  .cb-option input {\n    margin-top: 1px;\n    accent-color: var(--chill-barometer);\n  }\n\n  .cb-menu-actions {\n    display: flex;\n    justify-content: space-between;\n    gap: 8px;\n    padding: 10px;\n    border-top: 1px solid var(--chill-border);\n    background: rgba(255, 255, 255, 0.035);\n  }\n\n  .cb-menu-actions button,\n  .cb-reset {\n    cursor: pointer;\n    font-weight: 850;\n  }\n\n  .cb-menu-actions button {\n    padding: 8px 10px;\n    border: 1px solid var(--chill-border);\n    border-radius: 999px;\n    background: rgba(255, 255, 255, 0.05);\n    color: var(--chill-text);\n    font-size: 12px;\n  }\n\n  .cb-reset {\n    padding: 0 18px;\n    border-color: transparent;\n    background: linear-gradient(135deg, var(--chill-barometer), #7dd3fc);\n    color: #06111e;\n    white-space: nowrap;\n  }\n\n  .cb-kpis {\n    display: grid;\n    grid-template-columns: repeat(4, minmax(0, 1fr));\n    gap: 14px;\n  }\n\n  .cb-kpi,\n  .cb-card {\n    border: 1px solid var(--chill-border);\n    border-radius: var(--chill-radius-xl);\n    background:\n      radial-gradient(circle at 100% 0%, rgba(56, 189, 248, 0.08), transparent 34%),\n      linear-gradient(180deg, rgba(18, 39, 62, 0.96), rgba(11, 24, 41, 0.96));\n    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.23);\n  }\n\n  .cb-kpi {\n    min-height: 128px;\n    padding: 22px;\n    overflow: hidden;\n  }\n\n  .cb-kpi strong {\n    display: block;\n    margin-bottom: 9px;\n    color: var(--chill-text);\n    font-size: clamp(30px, 4vw, 44px);\n    line-height: 0.96;\n    letter-spacing: -0.06em;\n  }\n\n  .cb-kpi span {\n    display: block;\n    color: var(--chill-muted);\n    font-size: 13px;\n    line-height: 1.35;\n  }\n\n  .cb-card {\n    padding: clamp(20px, 3vw, 30px);\n  }\n\n  .cb-score-card {\n    display: grid;\n    grid-template-columns: minmax(190px, 250px) 1fr;\n    align-items: center;\n    gap: clamp(20px, 4vw, 40px);\n  }\n\n  .cb-gauge-wrap {\n    display: grid;\n    place-items: center;\n  }\n\n  .cb-gauge {\n    --cb-score-deg: 0deg;\n    --cb-gauge-color: var(--chill-barometer);\n    display: grid;\n    place-items: center;\n    width: min(230px, 56vw);\n    aspect-ratio: 1;\n    border-radius: 50%;\n    background:\n      conic-gradient(var(--cb-gauge-color) 0deg var(--cb-score-deg), rgba(255, 255, 255, 0.10) var(--cb-score-deg) 360deg);\n    box-shadow:\n      inset 0 0 0 1px rgba(255, 255, 255, 0.10),\n      0 20px 50px rgba(0, 0, 0, 0.30);\n  }\n\n  .cb-gauge-inner {\n    display: grid;\n    place-items: center;\n    align-content: center;\n    width: 72%;\n    aspect-ratio: 1;\n    border: 1px solid var(--chill-border);\n    border-radius: 50%;\n    background: #06111c;\n  }\n\n  .cb-gauge-inner span {\n    color: var(--chill-text);\n    font-size: clamp(44px, 7vw, 58px);\n    font-weight: 950;\n    line-height: 0.9;\n    letter-spacing: -0.08em;\n  }\n\n  .cb-gauge-inner small {\n    color: var(--chill-muted);\n    font-weight: 850;\n  }\n\n  .cb-eyebrow {\n    margin: 0 0 9px !important;\n    color: var(--chill-barometer);\n    font-size: 12px !important;\n    font-weight: 900;\n    letter-spacing: 0.16em;\n    text-transform: uppercase;\n  }\n\n  .cb-score-text h3,\n  .cb-section-head h3,\n  .cb-mini-insight h3 {\n    margin: 0;\n    color: var(--chill-text);\n    font-size: clamp(26px, 3.4vw, 38px);\n    line-height: 1.05;\n    font-weight: 800;\n    letter-spacing: -0.035em;\n  }\n\n  .cb-score-text p,\n  .cb-mini-insight p {\n    color: var(--chill-muted);\n    line-height: 1.6;\n  }\n\n  .cb-effect-strip,\n  .cb-legend {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 9px;\n    margin-top: 18px;\n  }\n\n  .cb-pill,\n  .cb-legend span {\n    display: inline-flex;\n    align-items: center;\n    gap: 8px;\n    padding: 8px 11px;\n    border: 1px solid var(--chill-border);\n    border-radius: 999px;\n    background: rgba(255, 255, 255, 0.055);\n    color: var(--chill-muted);\n    font-size: 12px;\n    font-weight: 850;\n  }\n\n  .cb-dot,\n  .cb-legend i {\n    flex: 0 0 auto;\n    width: 8px;\n    height: 8px;\n    border-radius: 50%;\n    background: var(--chill-barometer);\n  }\n\n  .cb-dot.pressure,\n  .cb-legend i.pressure {\n    background: #ff5d6c;\n  }\n\n  .cb-dot.protective,\n  .cb-legend i.protective {\n    background: #6ee7b7;\n  }\n\n  .cb-dot.mixed,\n  .cb-legend i.mixed {\n    background: #ffd84d;\n  }\n\n  .cb-dot.neutral {\n    background: rgba(255, 255, 255, 0.45);\n  }\n\n  .cb-grid-two {\n    display: grid;\n    grid-template-columns: minmax(0, 1.55fr) minmax(280px, 0.8fr);\n    gap: 18px;\n  }\n\n  .cb-mini-insight {\n    display: grid;\n    align-content: space-between;\n  }\n\n  .cb-section-head {\n    display: flex;\n    justify-content: space-between;\n    align-items: flex-start;\n    gap: 16px;\n    margin-bottom: 22px;\n  }\n\n  .cb-tabs {\n    display: flex;\n    flex-wrap: wrap;\n    justify-content: flex-end;\n    gap: 8px;\n  }\n\n  .cb-tab {\n    padding: 10px 13px;\n    border: 1px solid var(--chill-border);\n    border-radius: 999px;\n    background: rgba(255, 255, 255, 0.055);\n    color: var(--chill-muted);\n    cursor: pointer;\n    font-size: 12px;\n    font-weight: 850;\n    white-space: nowrap;\n  }\n\n  .cb-tab.active,\n  .cb-tab:hover {\n    border-color: transparent;\n    background: linear-gradient(135deg, var(--chill-barometer), #7dd3fc);\n    color: #071120;\n  }\n\n  .cb-levels,\n  .cb-bars,\n  .cb-results {\n    display: grid;\n    gap: 12px;\n  }\n\n  .cb-level-row,\n  .cb-bar-row {\n    display: grid;\n    grid-template-columns: minmax(130px, 250px) 1fr auto;\n    align-items: center;\n    gap: 12px;\n  }\n\n  .cb-level-label,\n  .cb-bar-label {\n    color: var(--chill-text);\n    font-size: 13px;\n    font-weight: 850;\n    line-height: 1.28;\n  }\n\n  .cb-track {\n    height: 13px;\n    overflow: hidden;\n    border: 1px solid rgba(255, 255, 255, 0.08);\n    border-radius: 999px;\n    background: rgba(255, 255, 255, 0.08);\n  }\n\n  .cb-fill {\n    width: 0%;\n    height: 100%;\n    border-radius: 999px;\n    background: linear-gradient(90deg, #38bdf8, #6ee7b7);\n    transition: width 0.35s ease;\n  }\n\n  .cb-fill.low {\n    background: linear-gradient(90deg, #38bdf8, #6ee7b7);\n  }\n\n  .cb-fill.medium {\n    background: linear-gradient(90deg, #6ee7b7, #ffd84d);\n  }\n\n  .cb-fill.high {\n    background: linear-gradient(90deg, #ffd84d, #ff9b52);\n  }\n\n  .cb-fill.critical {\n    background: linear-gradient(90deg, #ff9b52, #ff5d6c);\n  }\n\n  .cb-count {\n    color: var(--chill-muted);\n    font-size: 12px;\n    font-weight: 850;\n    white-space: nowrap;\n  }\n\n  .cb-result {\n    display: grid;\n    grid-template-columns: 1fr auto;\n    gap: 14px;\n    padding: 16px;\n    border: 1px solid var(--chill-border);\n    border-radius: 18px;\n    background: rgba(255, 255, 255, 0.045);\n  }\n\n  .cb-result h4 {\n    margin: 0 0 9px;\n    color: var(--chill-text);\n    font-size: 17px;\n    letter-spacing: -0.02em;\n  }\n\n  .cb-result h4 a {\n    color: var(--chill-text);\n    text-decoration: none;\n  }\n\n  .cb-result h4 a:hover {\n    color: var(--chill-barometer);\n  }\n\n  .cb-meta {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 7px;\n  }\n\n  .cb-meta span {\n    padding: 6px 8px;\n    border-radius: 999px;\n    background: rgba(255, 255, 255, 0.07);\n    color: var(--chill-muted);\n    font-size: 12px;\n    font-weight: 750;\n  }\n\n  .cb-result-score {\n    display: grid;\n    place-items: center;\n    align-content: center;\n    min-width: 74px;\n    height: 74px;\n    border: 1px solid rgba(56, 189, 248, 0.30);\n    border-radius: 18px;\n    background: rgba(56, 189, 248, 0.12);\n  }\n\n  .cb-result-score strong {\n    color: var(--chill-text);\n    font-size: 28px;\n    line-height: 1;\n    letter-spacing: -0.06em;\n  }\n\n  .cb-result-score small {\n    color: var(--chill-muted);\n    font-weight: 850;\n  }\n\n  .cb-empty {\n    padding: 16px;\n    border: 1px dashed var(--chill-border);\n    border-radius: 18px;\n    color: var(--chill-muted);\n    text-align: center;\n  }\n\n  @media (max-width: 1120px) {\n    .cb-controls {\n      position: relative;\n      top: auto;\n      grid-template-columns: 1fr;\n    }\n\n    .cb-filter-grid {\n      grid-template-columns: repeat(3, minmax(0, 1fr));\n    }\n  }\n\n  @media (max-width: 860px) {\n    .cb-hero,\n    .cb-filter-grid,\n    .cb-kpis,\n    .cb-grid-two,\n    .cb-score-card {\n      grid-template-columns: 1fr;\n    }\n\n    .cb-hero-badge {\n      min-width: 0;\n    }\n\n    .cb-section-head-responsive {\n      display: grid;\n    }\n\n    .cb-tabs {\n      justify-content: flex-start;\n    }\n\n    .cb-menu {\n      position: static;\n      min-width: 0;\n      margin-top: 9px;\n    }\n  }\n\n  @media (max-width: 560px) {\n    .cb-level-row,\n    .cb-bar-row,\n    .cb-result {\n      grid-template-columns: 1fr;\n      gap: 8px;\n    }\n\n    .cb-tabs {\n      display: grid;\n      grid-template-columns: 1fr 1fr;\n      width: 100%;\n    }\n\n    .cb-tab {\n      width: 100%;\n    }\n\n    .cb-effect-strip,\n    .cb-legend {\n      display: grid;\n    }\n    \n  }\n\n\n  \/* CHILL Barometer \u2014 leading thematic area KPI *\/\n  #chill-barometer-app .cb-kpi.cb-kpi-theme strong {\n    font-size: clamp(24px, 2.35vw, 34px) !important;\n    line-height: 1.08 !important;\n    letter-spacing: -0.035em !important;\n    max-width: 100% !important;\n    display: block !important;\n    overflow-wrap: normal !important;\n    word-break: normal !important;\n  }\n\n  @media (max-width: 560px) {\n    #chill-barometer-app .cb-kpi.cb-kpi-theme strong {\n      font-size: 28px !important;\n    }\n  }\n\n<\/style>\n\n<script>\n(function () {\n  const CONFIG = {\n    restEndpoint: window.location.origin + \"\/wp-json\/wp\/v2\/posts\",\n    perPage: 100,\n    taxonomies: {\n      thematic_area: [\"thematic_area\"],\n      country: [\"country\"],\n      righst_involved: [\"righst_involved\", \"rights_involved\"]\n    }\n  };\n\n  const STATIC_OPTIONS = {\n    thematic_area: [\n      \"Environmental Rights and Climate Protest\",\n      \"AI Surveillance and Digital Rights\",\n      \"Freedom of Expression and Media\",\n      \"Right to Protest and Civil Disobedience\",\n      \"Academic Freedom\",\n      \"Civil Society and NGOs\",\n      \"Migration Borders and Humanitarian Assistance\",\n      \"SLAPPs Defamation and Abusive Litigation\",\n      \"Security Public Order and Counter Terrorism\",\n      \"Labour Trade Unions and Social Mobilisation\",\n      \"Gender Vulnerability and Discrimination\",\n      \"Corporate Accountability and Business\"\n    ],\n    geographic_area: [\n      \"Europe\",\n      \"European Union\",\n      \"Council of Europe Area\",\n      \"North America\",\n      \"Latin America\",\n      \"Africa\",\n      \"Middle East and North Africa\",\n      \"Asia Pacific\",\n      \"Global Transnational\"\n    ],\n    righst_involved: [\n      \"Freedom of Expression\",\n      \"Freedom of Assembly\",\n      \"Freedom of Association\",\n      \"Privacy and Data Protection\",\n      \"Academic Freedom\",\n      \"Access to Justice Defence Rights\",\n      \"Fair Trial\",\n      \"Personal Liberty\",\n      \"Non Discrimination\",\n      \"Environmental Rights\",\n      \"Labour Rights\",\n      \"Property Economic Resources\",\n      \"Dignity Reputation\",\n      \"Democratic Participation\"\n    ],\n    effect_on_chilling_pressure: [\n      \"Increases Pressure\",\n      \"Reduces Pressure\",\n      \"Mixed or Ambiguous Effect\",\n      \"Neutral or No Clear Effect\",\n      \"Prevents Future Pressure\",\n      \"Removes Existing Pressure\",\n      \"Not Assessed\"\n    ],\n    chilling_effect_level: [\n      \"Low\",\n      \"Medium\",\n      \"High\",\n      \"Very High\",\n      \"Systemic\",\n      \"Not Assessed\"\n    ]\n  };\n\n  const FILTERS = [\n    { key: \"thematic_area\", label: \"Thematic area\", short: \"Theme\" },\n    { key: \"country\", label: \"Country\", short: \"Country\" },\n    { key: \"geographic_area\", label: \"Geographic area\", short: \"Area\" },\n    { key: \"righst_involved\", label: \"Rights involved\", short: \"Rights\" },\n    { key: \"effect_on_chilling_pressure\", label: \"Effect on chilling pressure\", short: \"Effect\" },\n    { key: \"chilling_effect_level\", label: \"Chilling effect level\", short: \"Level\" }\n  ];\n\n  const GROUP_LABELS = {\n    thematic_area: \"By thematic area\",\n    country: \"By country\",\n    geographic_area: \"By geographic area\",\n    righst_involved: \"By rights involved\"\n  };\n\n  const FIELD_ALIASES = {\n    righst_involved: [\"righst_involved\", \"rights_involved\"],\n    correct_or_mitigating_effect: [\"correct_or_mitigating_effect\", \"corrective_or_mitigating_effect\"],\n    barometer_source_reiliability: [\"barometer_source_reiliability\", \"barometer_source_reliability\"]\n  };\n\n  const root = document.getElementById(\"chill-barometer-app\");\n  const loading = document.getElementById(\"cb-loading\");\n  const shell = root.querySelector(\".cb-shell\");\n\n  const state = {\n    records: [],\n    filtered: [],\n    termsById: {},\n    filters: {},\n    groupBy: \"thematic_area\"\n  };\n\n  FILTERS.forEach(f => state.filters[f.key] = new Set());\n\n  const $ = (selector, base = document) => base.querySelector(selector);\n  const $$ = (selector, base = document) => Array.from(base.querySelectorAll(selector));\n\n  function escapeHtml(value) {\n    return String(value || \"\")\n      .replaceAll(\"&\", \"&amp;\")\n      .replaceAll(\"<\", \"&lt;\")\n      .replaceAll(\">\", \"&gt;\")\n      .replaceAll('\"', \"&quot;\")\n      .replaceAll(\"'\", \"&#039;\");\n  }\n\n  function stripHtml(value) {\n    const temp = document.createElement(\"div\");\n    temp.innerHTML = value || \"\";\n    return temp.textContent || temp.innerText || \"\";\n  }\n\n  function norm(value) {\n    return String(value || \"\").trim().toLowerCase();\n  }\n\n  function unique(values) {\n    return Array.from(new Set(values.filter(Boolean).map(v => String(v).trim()).filter(Boolean)));\n  }\n\n  function clamp(num, min, max) {\n    return Math.max(min, Math.min(max, num));\n  }\n\n  function numberField(acf, key) {\n    const raw = getAcfValue(acf, key);\n    if (raw === null || raw === undefined || raw === \"\") return null;\n    const n = Number(String(raw).replace(\",\", \".\"));\n    return Number.isFinite(n) ? n : null;\n  }\n\n  function getAcfValue(acf, key) {\n    const aliases = FIELD_ALIASES[key] || [key];\n    for (const candidate of aliases) {\n      if (acf && Object.prototype.hasOwnProperty.call(acf, candidate)) return acf[candidate];\n    }\n    return null;\n  }\n\n  function normalizeValue(value) {\n    if (value === null || value === undefined || value === \"\") return [];\n\n    if (Array.isArray(value)) return unique(value.flatMap(normalizeValue));\n\n    if (typeof value === \"object\") {\n      if (value.name) return [String(value.name)];\n      if (value.label) return [String(value.label)];\n      if (value.title && value.title.rendered) return [stripHtml(value.title.rendered)];\n      if (value.post_title) return [String(value.post_title)];\n      if (value.term_id && state.termsById[value.term_id]) return [state.termsById[value.term_id]];\n      if (value.id && state.termsById[value.id]) return [state.termsById[value.id]];\n      if (value.ID && state.termsById[value.ID]) return [state.termsById[value.ID]];\n      if (value.value && typeof value.value !== \"object\") return [String(value.value)];\n      return unique(Object.values(value).flatMap(normalizeValue));\n    }\n\n    if (typeof value === \"number\") return [state.termsById[value] || String(value)];\n\n    const str = String(value).trim();\n    if (!str) return [];\n\n    if (str.startsWith(\"[\") || str.startsWith(\"{\")) {\n      try { return normalizeValue(JSON.parse(str)); } catch (e) {}\n    }\n\n    return unique(str.split(\";\").map(v => v.trim()));\n  }\n\n  function getFieldArray(post, key) {\n    const acf = post.acf || {};\n    let values = normalizeValue(getAcfValue(acf, key));\n\n    if (!values.length) {\n      const aliases = FIELD_ALIASES[key] || [key];\n      for (const alias of aliases) {\n        if (post[alias]) {\n          values = normalizeValue(post[alias]);\n          break;\n        }\n      }\n    }\n\n    return values;\n  }\n\n  function getFieldSingle(post, key) {\n    return getFieldArray(post, key)[0] || \"\";\n  }\n\n  function scoreFromIndicators(acf, effect) {\n    const restrictiveKeys = [\n      \"measure_intensity\",\n      \"legal_uncertainty\",\n      \"sanctioning_risk\",\n      \"breadth_of_affected_subjects\",\n      \"vulnerability_of_affected_subjects\",\n      \"documented_deterrent_effect\",\n      \"public_visibility_exemplary_effect\",\n      \"replicability_of_the_measure\",\n      \"surveillance_or_data_collection\"\n    ];\n\n    const protectiveKeys = [\n      \"procedural_safeguards\",\n      \"protective_judicial_response\",\n      \"correct_or_mitigating_effect\"\n    ];\n\n    const restrictive = restrictiveKeys.map(k => numberField(acf, k)).filter(n => n !== null);\n    const protective = protectiveKeys.map(k => numberField(acf, k)).filter(n => n !== null);\n\n    const isProtective = [\"Reduces Pressure\", \"Prevents Future Pressure\", \"Removes Existing Pressure\"].includes(effect);\n\n    if (isProtective && protective.length) return Math.round((avg(protective) \/ 5) * 100);\n\n    if (restrictive.length) {\n      const base = avg(restrictive);\n      const reduction = protective.length ? avg(protective) * 0.35 : 0;\n      return Math.round((clamp(base - reduction, 0, 5) \/ 5) * 100);\n    }\n\n    return 0;\n  }\n\n  function levelFromScore(score) {\n    if (!score) return \"Not Assessed\";\n    if (score <= 25) return \"Low\";\n    if (score <= 50) return \"Medium\";\n    if (score <= 75) return \"High\";\n    if (score <= 90) return \"Very High\";\n    return \"Systemic\";\n  }\n\n  function avg(values) {\n    const valid = values.filter(n => Number.isFinite(n));\n    if (!valid.length) return 0;\n    return valid.reduce((a, b) => a + b, 0) \/ valid.length;\n  }\n\n  function effectType(effect) {\n    if (effect === \"Increases Pressure\") return \"pressure\";\n    if ([\"Reduces Pressure\", \"Prevents Future Pressure\", \"Removes Existing Pressure\"].includes(effect)) return \"protective\";\n    if (effect === \"Mixed or Ambiguous Effect\") return \"mixed\";\n    return \"neutral\";\n  }\n\n  function colorForScore(score) {\n    if (score <= 25) return \"#42c8ff\";\n    if (score <= 50) return \"#b7ff5b\";\n    if (score <= 75) return \"#ffd84d\";\n    if (score <= 90) return \"#ff9b52\";\n    return \"#ff5d6c\";\n  }\n\n  function fillClass(score) {\n    if (score <= 25) return \"low\";\n    if (score <= 50) return \"medium\";\n    if (score <= 75) return \"high\";\n    return \"critical\";\n  }\n\n  async function fetchJson(url) {\n    const response = await fetch(url, { credentials: \"same-origin\" });\n    if (!response.ok) throw new Error(\"REST error: \" + response.status + \" \" + url);\n    return {\n      data: await response.json(),\n      totalPages: Number(response.headers.get(\"X-WP-TotalPages\") || 1)\n    };\n  }\n\n  async function fetchAllPosts() {\n    const all = [];\n    let page = 1;\n    let totalPages = 1;\n\n    do {\n      const separator = CONFIG.restEndpoint.includes(\"?\") ? \"&\" : \"?\";\n      const url = CONFIG.restEndpoint + separator + \"per_page=\" + CONFIG.perPage + \"&page=\" + page + \"&acf_format=standard&_embed=1\";\n      const result = await fetchJson(url);\n      all.push(...result.data);\n      totalPages = result.totalPages || 1;\n      page++;\n    } while (page <= totalPages);\n\n    return all;\n  }\n\n  async function fetchTaxonomy(slugs) {\n    for (const slug of slugs) {\n      try {\n        const url = window.location.origin + \"\/wp-json\/wp\/v2\/\" + slug + \"?per_page=100\";\n        const result = await fetchJson(url);\n        result.data.forEach(term => {\n          if (term.id && term.name) state.termsById[term.id] = stripHtml(term.name);\n        });\n        return result.data.map(term => stripHtml(term.name));\n      } catch (e) {\n        continue;\n      }\n    }\n    return [];\n  }\n\n  async function fetchAllTaxonomies() {\n    const out = {};\n    for (const [key, slugs] of Object.entries(CONFIG.taxonomies)) out[key] = await fetchTaxonomy(slugs);\n    return out;\n  }\n\n  function normalizePost(post) {\n    const acf = post.acf || {};\n    const effect = getFieldSingle(post, \"effect_on_chilling_pressure\") || \"Not Assessed\";\n\n    let score = numberField(acf, \"total_barometer_score\");\n    if (score === null) score = scoreFromIndicators(acf, effect);\n    score = clamp(Math.round(score || 0), 0, 100);\n\n    const level = getFieldSingle(post, \"chilling_effect_level\") || levelFromScore(score);\n    const title = stripHtml(post.title && post.title.rendered ? post.title.rendered : post.title || \"Untitled record\");\n\n    return {\n      id: post.id,\n      title,\n      link: post.link || \"\",\n      year: getFieldSingle(post, \"year\"),\n      country: getFieldArray(post, \"country\"),\n      geographic_area: getFieldArray(post, \"geographic_area\"),\n      thematic_area: getFieldArray(post, \"thematic_area\"),\n      righst_involved: getFieldArray(post, \"righst_involved\"),\n      effect_on_chilling_pressure: effect,\n      chilling_effect_level: level,\n      barometer_status: getFieldSingle(post, \"barometer_status\") || \"Not Assessed\",\n      score,\n      searchText: [\n        title,\n        getFieldArray(post, \"country\").join(\" \"),\n        getFieldArray(post, \"geographic_area\").join(\" \"),\n        getFieldArray(post, \"thematic_area\").join(\" \"),\n        getFieldArray(post, \"righst_involved\").join(\" \"),\n        effect,\n        level\n      ].join(\" \").toLowerCase()\n    };\n  }\n\n  function buildFilterOptions(dynamicTaxOptions) {\n    const dynamicFromRecords = {};\n\n    FILTERS.forEach(filter => {\n      dynamicFromRecords[filter.key] = unique(\n        state.records.flatMap(record => {\n          const value = record[filter.key];\n          return Array.isArray(value) ? value : [value];\n        })\n      );\n    });\n\n    const options = {\n      thematic_area: unique([...(STATIC_OPTIONS.thematic_area || []), ...(dynamicTaxOptions.thematic_area || []), ...(dynamicFromRecords.thematic_area || [])]),\n      country: unique([...(dynamicTaxOptions.country || []), ...(dynamicFromRecords.country || [])]),\n      geographic_area: unique([...(STATIC_OPTIONS.geographic_area || []), ...(dynamicFromRecords.geographic_area || [])]),\n      righst_involved: unique([...(STATIC_OPTIONS.righst_involved || []), ...(dynamicTaxOptions.righst_involved || []), ...(dynamicFromRecords.righst_involved || [])]),\n      effect_on_chilling_pressure: unique([...(STATIC_OPTIONS.effect_on_chilling_pressure || []), ...(dynamicFromRecords.effect_on_chilling_pressure || [])]),\n      chilling_effect_level: unique([...(STATIC_OPTIONS.chilling_effect_level || []), ...(dynamicFromRecords.chilling_effect_level || [])])\n    };\n\n    renderFilterPanels(options);\n  }\n\n  function renderFilterPanels(options) {\n    const container = $(\"#cb-filter-panels\");\n    container.innerHTML = FILTERS.map(filter => {\n      const values = options[filter.key] || [];\n      const safeKey = escapeHtml(filter.key);\n\n      return `\n        <div class=\"cb-select\" data-select=\"${safeKey}\">\n          <button type=\"button\" class=\"cb-select-button\" aria-expanded=\"false\">\n            <span>\n              <small>${escapeHtml(filter.short)}<\/small>\n              <strong data-select-label=\"${safeKey}\">All ${escapeHtml(filter.short.toLowerCase())}<\/strong>\n            <\/span>\n            <i class=\"cb-caret\" aria-hidden=\"true\"><\/i>\n          <\/button>\n\n          <div class=\"cb-menu\">\n            <div class=\"cb-menu-scroll\">\n              ${values.length ? values.map(value => `\n                <label class=\"cb-option\">\n                  <input type=\"checkbox\" data-filter=\"${safeKey}\" value=\"${escapeHtml(value)}\">\n                  <span>${escapeHtml(value)}<\/span>\n                <\/label>\n              `).join(\"\") : `<div class=\"cb-empty\">No options available.<\/div>`}\n            <\/div>\n            <div class=\"cb-menu-actions\">\n              <button type=\"button\" data-clear=\"${safeKey}\">Clear<\/button>\n              <button type=\"button\" data-close-select>Done<\/button>\n            <\/div>\n          <\/div>\n        <\/div>\n      `;\n    }).join(\"\");\n\n    $$(\".cb-select-button\", container).forEach(button => {\n      button.addEventListener(\"click\", event => {\n        event.stopPropagation();\n        const current = button.closest(\".cb-select\");\n        $$(\".cb-select\", container).forEach(select => {\n          if (select !== current) {\n            select.classList.remove(\"open\");\n            const btn = select.querySelector(\".cb-select-button\");\n            if (btn) btn.setAttribute(\"aria-expanded\", \"false\");\n          }\n        });\n        current.classList.toggle(\"open\");\n        button.setAttribute(\"aria-expanded\", current.classList.contains(\"open\") ? \"true\" : \"false\");\n      });\n    });\n\n    $$(\"input[data-filter]\", container).forEach(input => {\n      input.addEventListener(\"change\", () => {\n        const key = input.dataset.filter;\n        if (input.checked) state.filters[key].add(input.value);\n        else state.filters[key].delete(input.value);\n        updateDropdownLabels();\n        applyFilters();\n      });\n    });\n\n    $$('[data-clear]', container).forEach(button => {\n      button.addEventListener(\"click\", event => {\n        event.stopPropagation();\n        const key = button.dataset.clear;\n        state.filters[key].clear();\n        $$(`input[data-filter=\"${key}\"]`, container).forEach(input => input.checked = false);\n        updateDropdownLabels();\n        applyFilters();\n      });\n    });\n\n    $$('[data-close-select]', container).forEach(button => {\n      button.addEventListener(\"click\", event => {\n        event.stopPropagation();\n        const select = button.closest(\".cb-select\");\n        select.classList.remove(\"open\");\n        const btn = select.querySelector(\".cb-select-button\");\n        if (btn) btn.setAttribute(\"aria-expanded\", \"false\");\n      });\n    });\n\n    document.addEventListener(\"click\", () => {\n      $$(\".cb-select\", container).forEach(select => {\n        select.classList.remove(\"open\");\n        const btn = select.querySelector(\".cb-select-button\");\n        if (btn) btn.setAttribute(\"aria-expanded\", \"false\");\n      });\n    });\n\n    updateDropdownLabels();\n  }\n\n  function updateDropdownLabels() {\n    FILTERS.forEach(filter => {\n      const label = $(`[data-select-label=\"${filter.key}\"]`);\n      if (!label) return;\n      const selected = Array.from(state.filters[filter.key] || []);\n      if (!selected.length) {\n        label.textContent = \"All \" + filter.short.toLowerCase();\n      } else if (selected.length === 1) {\n        label.textContent = selected[0];\n      } else {\n        label.textContent = selected.length + \" selected\";\n      }\n    });\n  }\n\n  function recordMatches(record) {\n    const search = norm($(\"#cb-search\").value);\n    if (search && !record.searchText.includes(search)) return false;\n\n    return FILTERS.every(filter => {\n      const selected = Array.from(state.filters[filter.key] || []);\n      if (!selected.length) return true;\n\n      const recordValue = record[filter.key];\n      const values = Array.isArray(recordValue) ? recordValue : [recordValue];\n\n      return selected.some(sel => values.some(v => norm(v) === norm(sel)));\n    });\n  }\n\n  function applyFilters() {\n    state.filtered = state.records.filter(recordMatches);\n    renderAll();\n  }\n\n  function renderAll() {\n    renderKpis();\n    renderGauge();\n    renderLevelDistribution();\n    renderGroupChart();\n    renderResults();\n  }\n\n  function getStats(records) {\n    const count = records.length;\n    const scores = records.map(r => r.score).filter(n => n > 0);\n    const average = Math.round(avg(scores));\n    const highCount = records.filter(r => r.score >= 51 || [\"High\", \"Very High\", \"Systemic\"].includes(r.chilling_effect_level)).length;\n\n    const pressure = records.filter(r => effectType(r.effect_on_chilling_pressure) === \"pressure\").length;\n    const protective = records.filter(r => effectType(r.effect_on_chilling_pressure) === \"protective\").length;\n    const mixed = records.filter(r => effectType(r.effect_on_chilling_pressure) === \"mixed\").length;\n    const neutral = records.filter(r => effectType(r.effect_on_chilling_pressure) === \"neutral\").length;\n\n    return { count, average, highCount, pressure, protective, mixed, neutral };\n  }\n\n  function mostFrequent(records, key) {\n    const map = new Map();\n    records.forEach(record => {\n      const values = Array.isArray(record[key]) ? record[key] : [record[key]];\n      values.filter(Boolean).forEach(value => map.set(value, (map.get(value) || 0) + 1));\n    });\n    const top = Array.from(map.entries()).sort((a, b) => b[1] - a[1])[0];\n    return top ? top[0] : \"\u2014\";\n  }\n\n  function renderKpis() {\n    const stats = getStats(state.filtered);\n    $(\"#cb-kpis\").innerHTML = `\n      <div class=\"cb-kpi\"><strong>${stats.count}<\/strong><span>filtered records<\/span><\/div>\n      <div class=\"cb-kpi\"><strong>${stats.average || 0}<\/strong><span>average score<\/span><\/div>\n      <div class=\"cb-kpi\"><strong>${stats.highCount}<\/strong><span>high \/ very high \/ systemic records<\/span><\/div>\n      <div class=\"cb-kpi cb-kpi-theme\"><strong>${escapeHtml(shortThemeLabel(mostFrequent(state.filtered, \"thematic_area\")))}<\/strong><span>leading thematic area<\/span><\/div>\n    `;\n  }\n\n  function renderGauge() {\n    const stats = getStats(state.filtered);\n    const score = stats.average || 0;\n    const gauge = $(\"#cb-gauge\");\n\n    gauge.style.setProperty(\"--cb-score-deg\", (score * 3.6) + \"deg\");\n    gauge.style.setProperty(\"--cb-gauge-color\", colorForScore(score));\n\n    $(\"#cb-gauge-score\").textContent = score;\n    $(\"#cb-score-title\").textContent = score ? labelForScore(score) : \"No data selected\";\n\n    $(\"#cb-effect-strip\").innerHTML = `\n      <span class=\"cb-pill\"><span class=\"cb-dot pressure\"><\/span>Pressure: ${stats.pressure}<\/span>\n      <span class=\"cb-pill\"><span class=\"cb-dot protective\"><\/span>Protective \/ corrective: ${stats.protective}<\/span>\n      <span class=\"cb-pill\"><span class=\"cb-dot mixed\"><\/span>Mixed \/ ambiguous: ${stats.mixed}<\/span>\n      <span class=\"cb-pill\"><span class=\"cb-dot neutral\"><\/span>Neutral \/ not assessed: ${stats.neutral}<\/span>\n    `;\n  }\n\n  function labelForScore(score) {\n    if (score <= 25) return \"Low intensity\";\n    if (score <= 50) return \"Medium intensity\";\n    if (score <= 75) return \"High intensity\";\n    if (score <= 90) return \"Very high intensity\";\n    return \"Systemic or exceptional intensity\";\n  }\n\n  function renderLevelDistribution() {\n    const levels = [\"Low\", \"Medium\", \"High\", \"Very High\", \"Systemic\", \"Not Assessed\"];\n    const total = state.filtered.length || 1;\n\n    $(\"#cb-level-distribution\").innerHTML = levels.map(level => {\n      const count = state.filtered.filter(r => r.chilling_effect_level === level).length;\n      const percentage = Math.round((count \/ total) * 100);\n      const scoreForClass = level === \"Low\" ? 20 : level === \"Medium\" ? 45 : level === \"High\" ? 70 : level === \"Very High\" ? 85 : level === \"Systemic\" ? 100 : 0;\n\n      return `\n        <div class=\"cb-level-row\">\n          <div class=\"cb-level-label\">${escapeHtml(level)}<\/div>\n          <div class=\"cb-track\"><div class=\"cb-fill ${fillClass(scoreForClass)}\" style=\"width:${percentage}%\"><\/div><\/div>\n          <div class=\"cb-count\">${count} \u00b7 ${percentage}%<\/div>\n        <\/div>\n      `;\n    }).join(\"\");\n  }\n\n  function renderGroupChart() {\n    const key = state.groupBy;\n    $(\"#cb-group-title\").textContent = GROUP_LABELS[key] || \"Aggregated view\";\n\n    const groups = new Map();\n    state.filtered.forEach(record => {\n      let values = record[key];\n      if (!Array.isArray(values)) values = [values];\n      if (!values.length || !values.some(Boolean)) values = [\"Unclassified\"];\n\n      values.filter(Boolean).forEach(value => {\n        if (!groups.has(value)) groups.set(value, []);\n        groups.get(value).push(record);\n      });\n    });\n\n    const rows = Array.from(groups.entries())\n      .map(([label, records]) => ({\n        label,\n        count: records.length,\n        average: Math.round(avg(records.map(r => r.score).filter(n => n > 0)))\n      }))\n      .sort((a, b) => b.average - a.average || b.count - a.count)\n      .slice(0, 18);\n\n    if (!rows.length) {\n      $(\"#cb-group-chart\").innerHTML = `<div class=\"cb-empty\">No records match the selected filters.<\/div>`;\n      return;\n    }\n\n    $(\"#cb-group-chart\").innerHTML = rows.map(row => `\n      <div class=\"cb-bar-row\">\n        <div class=\"cb-bar-label\">${escapeHtml(row.label)}<\/div>\n        <div class=\"cb-track\"><div class=\"cb-fill ${fillClass(row.average)}\" style=\"width:${row.average}%\"><\/div><\/div>\n        <div class=\"cb-count\">${row.average || 0}\/100 \u00b7 ${row.count} records<\/div>\n      <\/div>\n    `).join(\"\");\n  }\n\n  function renderResults() {\n    const records = [...state.filtered].sort((a, b) => b.score - a.score);\n    $(\"#cb-results-title\").textContent = records.length + \" records\";\n\n    if (!records.length) {\n      $(\"#cb-results\").innerHTML = `<div class=\"cb-empty\">No records found. Reduce the filters or check that ACF fields and taxonomies are exposed in the WordPress REST API.<\/div>`;\n      return;\n    }\n\n    $(\"#cb-results\").innerHTML = records.slice(0, 24).map(record => {\n      const title = escapeHtml(record.title);\n      const titleHtml = record.link ? `<a href=\"${escapeHtml(record.link)}\">${title}<\/a>` : title;\n      const meta = [\n        ...(record.country || []).slice(0, 2),\n        ...(record.geographic_area || []).slice(0, 1),\n        ...(record.thematic_area || []).slice(0, 2),\n        ...(record.righst_involved || []).slice(0, 2),\n        record.effect_on_chilling_pressure,\n        record.chilling_effect_level\n      ].filter(Boolean);\n\n      return `\n        <article class=\"cb-result\">\n          <div>\n            <h4>${titleHtml}<\/h4>\n            <div class=\"cb-meta\">${meta.map(item => `<span>${escapeHtml(item)}<\/span>`).join(\"\")}<\/div>\n          <\/div>\n          <div class=\"cb-result-score\"><strong>${record.score || 0}<\/strong><small>\/100<\/small><\/div>\n        <\/article>\n      `;\n    }).join(\"\");\n\n    if (records.length > 24) {\n      $(\"#cb-results\").insertAdjacentHTML(\"beforeend\", `<div class=\"cb-empty\">Showing the first 24 records ordered by score. Use the filters to narrow the results.<\/div>`);\n    }\n  }\n\n  function shorten(value, max) {\n    const str = String(value || \"\");\n    return str.length > max ? str.slice(0, max - 1) + \"\u2026\" : str;\n  }\n\n\n\n  function shortThemeLabel(value) {\n    const label = String(value || \"\");\n\n    const labels = {\n      \"AI Surveillance and Digital Rights\": \"AI & Digital Rights\",\n      \"Environmental Rights and Climate Protest\": \"Climate Protest\",\n      \"Freedom of Expression and Media\": \"Expression & Media\",\n      \"Right to Protest and Civil Disobedience\": \"Protest & Disobedience\",\n      \"Migration Borders and Humanitarian Assistance\": \"Migration & Borders\",\n      \"SLAPPs Defamation and Abusive Litigation\": \"SLAPPs & Litigation\",\n      \"Security Public Order and Counter Terrorism\": \"Security & Public Order\",\n      \"Labour Trade Unions and Social Mobilisation\": \"Labour & Unions\",\n      \"Gender Vulnerability and Discrimination\": \"Gender & Equality\",\n      \"Corporate Accountability and Business\": \"Corporate Accountability\",\n      \"Civil Society and NGOs\": \"Civil Society\",\n      \"Academic Freedom\": \"Academic Freedom\"\n    };\n\n    return labels[label] || shorten(label, 24);\n  }\n\n  function bindEvents() {\n    $(\"#cb-search\").addEventListener(\"input\", applyFilters);\n\n    $(\"#cb-reset\").addEventListener(\"click\", () => {\n      $(\"#cb-search\").value = \"\";\n      FILTERS.forEach(filter => state.filters[filter.key].clear());\n      $$(\"input[data-filter]\").forEach(input => input.checked = false);\n      updateDropdownLabels();\n      applyFilters();\n    });\n\n    $$(\".cb-tab\").forEach(button => {\n      button.addEventListener(\"click\", () => {\n        $$(\".cb-tab\").forEach(btn => btn.classList.remove(\"active\"));\n        button.classList.add(\"active\");\n        state.groupBy = button.dataset.group;\n        renderGroupChart();\n      });\n    });\n  }\n\n  async function init() {\n    try {\n      const dynamicTaxOptions = await fetchAllTaxonomies();\n      const posts = await fetchAllPosts();\n\n      state.records = posts\n        .map(normalizePost)\n        .filter(record => {\n          return (\n            record.score > 0 ||\n            record.barometer_status !== \"Not Assessed\" ||\n            record.thematic_area.length ||\n            record.righst_involved.length\n          );\n        });\n\n      buildFilterOptions(dynamicTaxOptions);\n      bindEvents();\n\n      loading.hidden = true;\n      shell.hidden = false;\n      applyFilters();\n    } catch (error) {\n      console.error(error);\n      loading.innerHTML = `<strong>Unable to load the Barometer.<\/strong><br>Check that the post type, ACF fields, and taxonomies are exposed in the WordPress REST API.`;\n    }\n  }\n\n  init();\n})();\n<\/script>\t\t\t\t<\/div>\n\t\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>CHILL Barometer CHILL Barometer Measuring chilling pressure Explore the intensity of chilling pressure across thematic areas, countries, geographic areas, and rights involved. Interactive Atlas-based assessment Loading CHILL Atlas records\u2026 Search Reset 0 \/100 Average intensity No data selected The score aggregates the filtered records. For restrictive measures, it indicates chilling pressure. For protective measures, it [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"ai_generated_summary":"","wpai_meta_description":"","footnotes":""},"class_list":["post-332","page","type-page","status-publish","hentry"],"acf":[],"_hostinger_reach_plugin_has_subscription_block":false,"_hostinger_reach_plugin_is_elementor":false,"_links":{"self":[{"href":"https:\/\/chill-lab.eu\/it\/wp-json\/wp\/v2\/pages\/332","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/chill-lab.eu\/it\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/chill-lab.eu\/it\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/chill-lab.eu\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/chill-lab.eu\/it\/wp-json\/wp\/v2\/comments?post=332"}],"version-history":[{"count":13,"href":"https:\/\/chill-lab.eu\/it\/wp-json\/wp\/v2\/pages\/332\/revisions"}],"predecessor-version":[{"id":576,"href":"https:\/\/chill-lab.eu\/it\/wp-json\/wp\/v2\/pages\/332\/revisions\/576"}],"wp:attachment":[{"href":"https:\/\/chill-lab.eu\/it\/wp-json\/wp\/v2\/media?parent=332"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}