| Server IP : 127.0.0.1 / Your IP : 216.73.216.109 Web Server : Apache/2.4.54 (Win64) OpenSSL/1.1.1q PHP/8.1.10 System : Windows NT DESKTOP-E5T4RUN 10.0 build 19045 (Windows 10) AMD64 User : SERVERWEB ( 0) PHP Version : 8.1.10 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : C:/laragon/www/modules/unidades/assets/redMonica/ |
Upload File : |
<!DOCTYPE html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title>GAMQ-RED MONICA</title>
<meta name="description" content="">
<meta name="author" content="">
<!-- Mobile Specific Metas -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<!-- Favicons -->
<link rel="shortcut icon" href="/assets/images/brand/logo.png">
<!-- FONTS -->
<link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Roboto:100,300,400,400italic,700'>
<link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Patua+One:100,300,400,400italic,700'>
<link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Lato:400,400italic,700,700italic,900'>
<link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Montserrat:100,200,300,400,400italic,500,700,700italic'>
<!-- CSS -->
<link rel='stylesheet' href='/assets/css/global.css'>
<link rel='stylesheet' href='css/structure.css'>
<link rel='stylesheet' href='css/eco2.css'>
<link rel='stylesheet' href='css/custom.css'>
<script src="/assets/js/lib/jquery-3.7.1.min.js"></script>
<script>
$(function(){
$("#footer").load("/modules/unidades/footer.php");
$("#header").load("header.html");
});
</script>
</head>
<body class="style-simple button-default layout-full-width if-zoom if-border-hide no-content-padding no-shadows header-transparent minimalist-header-no sticky-tb-color ab-hide subheader-both-center menu-link-color menuo-right menuo-arrows menuo-no-borders mobile-tb-hide mobile-mini-mr-ll mobile-header-mini mobile-tr-header">
<div id="Wrapper">
<div id="header"></div>
<div id="Content">
<div class="content_wrapper clearfix">
<div class="sections_group">
<div class="section mcb-section" style="padding:0; position:relative; overflow:hidden;">
<div class="interactive-air-quality" style="background-image:url(/assets/images/home/hero/home5.png); background-repeat:no-repeat; background-position:center; min-height:70vh; position:relative; padding:80px 100px;">
<div class="bg-elements" style="position:absolute; top:0; left:0; width:100%; height:100%; pointer-events:none; z-index:1;">
<div class="circle" style="position:absolute; width:80px; height:80px; border-radius:50%; background:rgba(255,255,255,0.1); top:10%; left:10%; animation:float 6s ease-in-out infinite;"></div>
</div>
<!-- Current AQI Display -->
<div class="section_wrapper mcb-section-inner" style="position:relative; z-index:2;">
<div class="wrap mcb-wrap one valign-top clearfix">
<div class="mcb-wrap-inner">
<div class="column mcb-column one column_column align_center" style="margin-bottom:0px">
<h2 style="color:white; font-size:2.5em; font-weight:300; margin-bottom:20px; text-shadow:0 2px 4px rgba(0,0,0,0.3);">
MONITOREO DE CALIDAD DEL AIRE</h2>
<p style="color:rgba(255,255,255,0.9); font-size:1.2em;">Datos actualizados del sistema de monitoreo de Quillacollo</p>
</div>
<div class="column mcb-column one-third column_column" style="margin-top:30px;">
<div class="column_attr clearfix align_center air-quality-card" style="background-color:rgba(255,255,255,0.9); padding:30px; border-radius:10px; box-shadow: 0 10px 30px rgba(0,0,0,0.1);">
<h3 style="color:#1e6b52;">Índice de Calidad de Aire</h3>
<div id="aqi-cloud-container" style="position:relative; width:150px; height:150px; margin:20px auto;">
<div class="aqi-cloud" id="current-aqi" style="width:100%; height:100%; display:flex; flex-direction:column; justify-content:center; align-items:center; color:#333; font-weight:bold; transition: all 0.5s ease; position:relative;">
<div id="cloud-display" style="position:relative; width:100%; height:100%;"></div>
</div>
</div>
<p id="aqi-description" style="color:#333; margin-top:50px; font-size:15px; line-height:1.4;"></p>
<div style="margin-top:10px; font-size:13px; color:#666;">
<span id="update-time"></span><br>
<span id="station-name"></span>
</div>
</div>
</div>
<!-- Pollutant Levels -->
<div class="column mcb-column one-third column_column" style="margin-top:30px;">
<div class="column_attr clearfix air-quality-card" style="background-color:rgba(255,255,255,0.9); padding:30px; border-radius:10px; height:100%;">
<h3 style="color:#1e6b52; text-align:center;">Contaminantes Principales</h3>
<div id="pollutants-container" class="pollutants-container" style="margin-top:20px;">
<div class="loading-pollutants" style="text-align:center; padding:0px;">
<p>Cargando datos de contaminantes...</p>
</div>
</div>
<div style="font-size:13px; color:#666; text-align:center">
<span>Últimas lecturas</span>
</div>
</div>
</div>
<!-- Health Recommendations -->
<div class="column mcb-column one-third column_column" style="margin-top:30px;">
<div class="column_attr clearfix air-quality-card" style="background-color:rgba(255,255,255,0.9); padding:30px; border-radius:10px; height:100%;">
<h3 style="color:#1e6b52; text-align:center;">Recomendaciones</h3>
<div style="background-color:#FFF3E0; padding:15px; border-radius:8px; margin-bottom:15px;">
<h4 style="color:#FF9800; margin-top:0; display:flex; align-items:center;">
<span style="margin-right:8px;">👥</span> Para toda la población
</h4>
<p id="general-recommendation" style="margin-bottom:0;"></p>
</div>
<div class="risk-groups-container">
<h4 style="color:#F44336; margin-top:0; margin-bottom:15px; display:flex; align-items:center;">
<span style="margin-right:8px;">⚠️</span> Grupos de riesgo
<span class="scroll-arrows" style="margin-left:auto;">
<button class="scroll-left" aria-label="Scroll left">◀</button>
<button class="scroll-right" aria-label="Scroll right">▶</button>
</span>
</h4>
<div class="risk-groups-scroller">
<div class="risk-groups-wrapper" id="risk-groups-wrapper">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- AQI Classification Section -->
<div class="large-screen-only">
<div class="section mcb-section" style="padding:80px 20px; background:linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);">
<div class="section_wrapper mcb-section-inner">
<div class="wrap mcb-wrap one valign-top clearfix">
<div class="mcb-wrap-inner">
<div class="column mcb-column one column_column">
<div class="column_attr clearfix align_center">
<h2 style="color:#1e6b52; font-weight:bold; margin-bottom:10px;">CLASIFICACIÓN DEL ÍNDICE ICA</h2>
<p style="font-size:18px; color:#666;">Interpretación de los niveles de calidad del aire</p>
</div>
</div>
<div class="column mcb-column one column_column">
<div class="column_attr clearfix">
<div style="overflow-x:auto; border-radius:15px; box-shadow:0 10px 30px rgba(0,0,0,0.1);">
<table id="aqiTable" style="width:100%; border-collapse:collapse; font-size:16px; background:white;">
<thead>
<tr style="background:linear-gradient(135deg, #1e6b52, #51A3BC); color:#fff;">
<th style="padding:20px; text-align:center; font-weight:bold; letter-spacing:1px;">ICA</th>
<th style="padding:20px; text-align:center; font-weight:bold; letter-spacing:1px;">CLASIFICACIÓN</th>
<th style="padding:20px; text-align:left; font-weight:bold; letter-spacing:1px;">RECOMENDACIONES</th>
<th style="padding:20px; text-align:center; font-weight:bold; letter-spacing:1px;">ESTADO</th>
</tr>
</thead>
<tbody id="aqiTableBody">
</tbody>
</table>
</div>
</div>
</div>
<!-- Enhanced Risk Groups -->
<div class="column mcb-column one column_column" style="margin-top:50px;">
<div class="column_attr clearfix" style="background:linear-gradient(135deg, #e8f5e9, #f1f8e9); padding:30px; border-radius:15px; border-left:5px solid #1e6b52; box-shadow:0 5px 15px rgba(0,0,0,0.1);">
<h3 style="color:#1e6b52; text-transform:uppercase; margin-bottom:20px; display:flex; align-items:center; gap:10px;">
<span style="font-size:1.5em;">👥</span> Grupos de Riesgo
</h3>
<p style="margin-bottom:20px; font-weight:600; color:#333;"><strong>Defínase como grupo de riesgo:</strong></p>
<div id="dynamicRiskGroups" style="display:grid; grid-template-columns:repeat(auto-fit, minmax(250px, 1fr)); gap:15px;">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Interactive Buttons -->
<div class="small-screen-only">
<div class="section mcb-section" style="padding:0; position:relative; overflow:hidden;">
<div class="interactive-air-quality" style="background: linear-gradient(135deg, #4a9eff 0%, #1e6b52 100%); min-height:auto; position:relative; padding:50px 0;">
<div class="bg-elements" style="position:absolute; top:0; left:0; width:100%; height:80%; pointer-events:none; z-index:1;">
<div class="circle" style="position:absolute; width:80px; height:80px; border-radius:50%; background:rgba(255,255,255,0.1); top:10%; left:10%; animation:float 6s ease-in-out infinite;"></div>
<div class="circle" style="position:absolute; width:60px; height:60px; border-radius:50%; background:rgba(255,255,255,0.1); top:20%; right:15%; animation:float 6s ease-in-out infinite -2s;"></div>
<div class="circle" style="position:absolute; width:100px; height:100px; border-radius:50%; background:rgba(255,255,255,0.1); bottom:20%; left:20%; animation:float 6s ease-in-out infinite -4s;"></div>
<div class="circle" style="position:absolute; width:40px; height:40px; border-radius:50%; background:rgba(255,255,255,0.1); bottom:30%; right:25%; animation:float 6s ease-in-out infinite -1s;"></div>
</div>
<div class="section_wrapper mcb-section-inner" style="position:relative; z-index:2;">
<div class="wrap mcb-wrap one valign-top clearfix">
<div class="mcb-wrap-inner">
<div class="column mcb-column one-second column_column align_center" style="margin-bottom:50px;">
<div class="air-buttons" style="display:grid; grid-template-columns:repeat(auto-fit, minmax(200px, 1fr)); gap:20px; max-width:1000px; margin:0 auto;">
</div>
</div>
<div class="column mcb-column one-second column_column align_center">
<div id="airInfo" class="info-box" style="background:rgba(255,255,255,0.95); backdrop-filter:blur(20px); border-radius:20px; padding:40px; margin:0 auto; max-width:900px; border:1px solid rgba(255,255,255,0.3); box-shadow:0 20px 40px rgba(0,0,0,0.1); opacity:1; transform:translateY(0); transition:all 0.5s ease;">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- recomendaciones de salud -->
<div class="section mcb-section" id="#recomendaciones" style="padding-top:80px; padding-bottom:80px; background-color:#f8f8f8;">
<div class="section_wrapper mcb-section-inner">
<div class="wrap mcb-wrap one valign-top clearfix">
<div class="mcb-wrap-inner">
<div class="column mcb-column one column_column">
<div class="column_attr clearfix align_center">
<h2>¿CÓMO AFECTA LA CALIDAD DEL AIRE A TU SALUD?</h2>
<p style="max-width:800px; margin:0 auto;">Según la Organización Panamericana de la Salud (OPS), la contaminación del aire es un riesgo ambiental significativo para la salud en Quillacollo y toda la región.</p>
</div>
</div>
<div class="column mcb-column one-third column_column">
<div class="column_attr clearfix" style="background-color:#fff; padding:30px; border-radius:10px; height:100%; box-shadow:0 5px 15px rgba(0,0,0,0.05);">
<div style="width:60px; height:60px; background-color:#e3f2fd; border-radius:50%; display:flex; justify-content:center; align-items:center; margin-bottom:20px;">
<img src="/assets/images/units/red-monica/icon-respiratory.png" alt="Problemas respiratorios" width="40">
</div>
<h3 style="color:#1e6b52;">Problemas Respiratorios</h3>
<p>La exposición a PM10 y PM2.5 puede causar asma, bronquitis y otras enfermedades pulmonares obstructivas crónicas (EPOC). En Quillacollo, estas partículas provienen principalmente del parque automotor y quemas.</p>
</div>
</div>
<div class="column mcb-column one-third column_column">
<div class="column_attr clearfix" style="background-color:#fff; padding:30px; border-radius:10px; height:100%; box-shadow:0 5px 15px rgba(0,0,0,0.05);">
<div style="width:60px; height:60px; background-color:#e8f5e9; border-radius:50%; display:flex; justify-content:center; align-items:center; margin-bottom:20px;">
<img src="/assets/images/units/red-monica/icon-heart.png" alt="Problemas cardiovasculares" width="40">
</div>
<h3 style="color:#1e6b52;">Enfermedades Cardiovasculares</h3>
<p>Los contaminantes como el NO₂ y el CO están asociados con mayor riesgo de infartos, hipertensión arterial y otras enfermedades del corazón. La zona de la avenida Blanco Galindo es particularmente afectada por estas emisiones.</p>
</div>
</div>
<div class="column mcb-column one-third column_column">
<div class="column_attr clearfix" style="background-color:#fff; padding:30px; border-radius:10px; height:100%; box-shadow:0 5px 15px rgba(0,0,0,0.05);">
<div style="width:60px; height:60px; background-color:#fff3e0; border-radius:50%; display:flex; justify-content:center; align-items:center; margin-bottom:20px;">
<img src="/assets/images/units/red-monica/icon-brain.png" alt="Efectos neurológicos" width="40">
</div>
<h3 style="color:#1e6b52;">Efectos Neurológicos</h3>
<p>Estudios recientes muestran que la exposición prolongada a contaminantes puede afectar el desarrollo cognitivo en niños y aumentar el riesgo de enfermedades neurodegenerativas en adultos mayores.</p>
</div>
</div>
<div class="column mcb-column one column_column" style="margin-top:40px;">
<div class="column_attr clearfix" style="background-color:#e8f5e9; padding:20px; border-radius:10px;">
<h4 style="color:#1e6b52; margin-bottom:15px;">Poblaciones Vulnerables:</h4>
<div style="display:flex; flex-wrap:wrap; justify-content:space-around;">
<div style="margin:10px; text-align:center;">
<div style="font-size:18px; font-weight:bold;">👶 15,000 niños</div>
<div style="font-size:14px;">menores de 5 años</div>
</div>
<div style="margin:10px; text-align:center;">
<div style="font-size:18px; font-weight:bold;">👵 8,200 adultos</div>
<div style="font-size:14px;">mayores de 65 años</div>
</div>
<div style="margin:10px; text-align:center;">
<div style="font-size:18px; font-weight:bold;">🏥 3,500 personas</div>
<div style="font-size:14px;">con enfermedades crónicas</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="section mcb-section" style="padding-top:80px; padding-bottom:80px; background-color:#f0f7f4;">
<div class="section_wrapper mcb-section-inner">
<div class="wrap mcb-wrap one valign-top clearfix">
<div class="mcb-wrap-inner">
<div class="column mcb-column one column_column">
<div class="column_attr clearfix align_center">
<h2>RECOMENDACIONES PARA DÍAS DE CONTAMINACIÓN</h2>
<p>Consejos prácticos para proteger tu salud según los niveles de calidad del aire</p>
</div>
</div>
<div class="column mcb-column one-third column_column">
<div class="column_attr clearfix" style="background-color:#fff; padding:25px; border-radius:10px; height:100%; box-shadow:0 5px 15px rgba(0,0,0,0.05);">
<div style="display:flex; align-items:center; margin-bottom:15px;">
<div style="width:40px; height:40px; background-color:#e8f5e9; border-radius:50%; display:flex; justify-content:center; align-items:center; margin-right:15px;">
<span style="color:#1e6b52; font-weight:bold;">1</span>
</div>
<h3 style="margin:0; color:#1e6b52;">Para toda la población</h3>
</div>
<ul style="padding-left:20px;">
<li>Evita actividades físicas intensas al aire libre cuando el ICA sea "Moderado" o superior</li>
<li>Cierra ventanas cuando los niveles de PM10 sean altos</li>
<li>Usa mascarilla N95 en días de muy mala calidad del aire</li>
<li>Mantente hidratado para ayudar a tu sistema respiratorio</li>
</ul>
</div>
</div>
<div class="column mcb-column one-third column_column">
<div class="column_attr clearfix" style="background-color:#fff; padding:25px; border-radius:10px; height:100%; box-shadow:0 5px 15px rgba(0,0,0,0.05);">
<div style="display:flex; align-items:center; margin-bottom:15px;">
<div style="width:40px; height:40px; background-color:#e3f2fd; border-radius:50%; display:flex; justify-content:center; align-items:center; margin-right:15px;">
<span style="color:#1e6b52; font-weight:bold;">2</span>
</div>
<h3 style="margin:0; color:#1e6b52;">Para grupos sensibles</h3>
</div>
<ul style="padding-left:20px;">
<li>Niños, adultos mayores y personas con enfermedades respiratorias deben limitar su exposición en días con ICA > 100</li>
<li>Consulta con tu médico sobre medidas adicionales de protección</li>
<li>Considera el uso de purificadores de aire en interiores</li>
<li>Evita salir durante las horas pico de contaminación (7-9am y 5-7pm)</li>
</ul>
</div>
</div>
<div class="column mcb-column one-third column_column">
<div class="column_attr clearfix" style="background-color:#fff; padding:25px; border-radius:10px; height:100%; box-shadow:0 5px 15px rgba(0,0,0,0.05);">
<div style="display:flex; align-items:center; margin-bottom:15px;">
<div style="width:40px; height:40px; background-color:#fff3e0; border-radius:50%; display:flex; justify-content:center; align-items:center; margin-right:15px;">
<span style="color:#1e6b52; font-weight:bold;">3</span>
</div>
<h3 style="margin:0; color:#1e6b52;">Para reducir tu contribución</h3>
</div>
<ul style="padding-left:20px;">
<li>Prefiere el transporte público, bicicleta o caminar</li>
<li>Mantén tu vehículo en buen estado y realiza controles de emisiones</li>
<li>Evita quemar basura o residuos agrícolas</li>
<li>Reporta fuentes de contaminación evidentes al municipio</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="footer"></div>
</div>
<!-- JS -->
<script src="/assets/js/jquery-3.6.0.min.js"></script>
<script src="/assets/js/jquery-migrate-3.4.0.min.js"></script>
<script src="/assets/js/mfn.menu.js"></script>
<script src="/assets/js/jquery.plugins.js"></script>
<script src="/assets/js/jquery.jplayer.min.js"></script>
<script src="/assets/js/animations/animations.js"></script>
<script src="/assets/js/translate3d.js"></script>
<script src="/assets/js/scripts.js"></script>
<script src="/assets/js/email.js"></script>
<script>
let currentCategories = [];
$(document).ready(function() {
$.getJSON("data.php", function(data) {
window.currentCategories = data.indicesList;
const formattedDate = formatDate(data.fecha);
$('#update-time').text("Actualizado el " + formattedDate);
const cloudHtml = createExpressiveCloud(data.ica.clasificacion, data.ica.color, data.ica.valor);
$('#cloud-display').html(cloudHtml);
$('#aqi-status').text(data.ica.clasificacion);
$('#aqi-description').text(data.ica.descripcion);
const generalRec = data.ica.recomendaciones_gral || "No hay recomendaciones generales disponibles.";
$('#general-recommendation').text(generalRec);
$('#risk-groups-wrapper').empty();
const uniqueGroups = {};
if (data.ica.grupos_riesgo) {
data.ica.grupos_riesgo.forEach(group => {
if (!uniqueGroups[group.grupo]) {
uniqueGroups[group.grupo] = group.recomendacion;
}
});
for (const [groupName, recommendation] of Object.entries(uniqueGroups)) {
$('#risk-groups-wrapper').append(`
<div class="risk-group-card">
<div style="font-weight:600; color:#1e6b52; margin-bottom:8px; display:flex; align-items:center;">
<span style="margin-right:8px;">${getEmojiForGroup(groupName)}</span>
${groupName}
</div>
<div style="font-size:14px; color:#555;">
${recommendation}
</div>
</div>
`);
}
}
const pollutantsContainer = $('#pollutants-container');
pollutantsContainer.empty();
const latestContaminants = getLatestContaminantMeasurements(data.monitoringDataList);
if (latestContaminants.length > 0) {
let worstContaminant = null;
let highestPercentage = 0;
const priorityContaminants = ['PM2.5', 'PM10'];
const sortedContaminants = latestContaminants.sort((a, b) => {
const aPriority = priorityContaminants.includes(a.contaminanteDto.nombre) ? 0 : 1;
const bPriority = priorityContaminants.includes(b.contaminanteDto.nombre) ? 0 : 1;
return aPriority - bPriority;
});
sortedContaminants.forEach(pollutant => {
const category = data.indicesList.find(c => c.categoria === pollutant.categoriaCalculada);
const percentage = getContaminantPercentage(pollutant.valor, category.valorMaximo);
const progressClass = getCategoryProgressClass(pollutant.categoriaCalculada);
const color = getCategoryColor(pollutant.valor, data.indicesList);
if (percentage > highestPercentage) {
highestPercentage = percentage;
worstContaminant = pollutant;
}
const pollutantHtml = `
<div class="pollutant-level" style="margin-bottom: 15px;">
<div style="display:flex; justify-content:space-between; margin-bottom:8px; align-items:center;">
<span style="font-weight:bold; display:flex; align-items:center; font-size:16px;">
<span class="pollutant-icon" style="margin-right:10px; font-size:20px;">${getContaminantIcon(pollutant.contaminanteDto.nombre)}</span>
${pollutant.contaminanteDto.nombre}
</span>
<span class="pollutant-value" style="font-weight:700; background-color: ${color}; color: ${getContrastColor(color)}; padding: 4px 12px; border-radius: 15px; font-size:16px;">
${pollutant.valor.toFixed(0)} µg/m³
</span>
</div>
<div style="height:15px; background:#e0e0e0; border-radius:8px; overflow:hidden; margin-bottom:5px;">
<div class="progress-bar ${progressClass}" style="height:100%; background-color: ${color}; border-radius:8px; width:${percentage}%; transition: width 1s ease;"></div>
</div>
<div style="display:flex; justify-content:space-between; margin-top:5px;">
<span style="font-size:13px; color:#666;">${category.valorMinimo} µg/m³</span>
<span style="font-size:13px; color:#666;">Límite: ${category.valorMaximo} µg/m³</span>
</div>
</div>
`;
pollutantsContainer.append(pollutantHtml);
});
if (worstContaminant && worstContaminant.estacionDto) {
$('#station-name').text(`Estación: ${worstContaminant.estacionDto.nombre}`);
}
} else {
pollutantsContainer.html(`
<div class="no-pollutant-data" style="text-align:center; padding:20px;">
<p>No hay datos de contaminantes disponibles</p>
</div>
`);
}
$('.scroll-left').on('click', function() {
const container = $(this).closest('.risk-groups-container').find('.risk-groups-scroller');
container.animate({scrollLeft: container.scrollLeft() - 200}, 300);
});
$('.scroll-right').on('click', function() {
const container = $(this).closest('.risk-groups-container').find('.risk-groups-scroller');
container.animate({scrollLeft: container.scrollLeft() + 200}, 300);
});
let touchStartX = 0;
$('.risk-groups-scroller').on('touchstart', function(e) {
touchStartX = e.originalEvent.touches[0].clientX;
}).on('touchmove', function(e) {
const touchX = e.originalEvent.touches[0].clientX;
$(this).scrollLeft($(this).scrollLeft() + (touchStartX - touchX));
touchStartX = touchX;
});
let rowsHtml = "";
data.indicesList.forEach(item => {
let estadoIcon = "";
let estadoColor = "";
switch(item.categoria.toUpperCase()) {
case "BUENA":
estadoIcon = "✓";
estadoColor = "#4CAF50";
break;
case "REGULAR":
estadoIcon = "⚠";
estadoColor = "#FFC107";
break;
case "MALA":
estadoIcon = "⚠";
estadoColor = "#FF9800";
break;
case "MUY MALA":
estadoIcon = "🚨";
estadoColor = "#F44336";
break;
default:
estadoIcon = "";
estadoColor = "#000";
}
rowsHtml += `
<tr style="border-bottom:1px solid #eee; transition:all 0.3s ease;"
onmouseover="this.style.backgroundColor='#f0f0f0'"
onmouseout="this.style.backgroundColor=''">
<td style="padding:18px; background:linear-gradient(135deg, ${item.color}, ${item.color}); color:#fff; font-weight:bold; text-align:center; border-radius:8px; margin:5px;">
${item.valorMinimo} - ${item.valorMaximo}
</td>
<td style="padding:18px; text-align:center; font-weight:600; color:#333;">${item.categoria}</td>
<td style="padding:18px; color:#555; line-height:1.5;">
${item.descripcion}<br>
<strong>Recomendación general:</strong> ${item.recomendacion}
</td>
<td style="padding:18px; text-align:center;">
<span style="color:${estadoColor}; font-size:1.5em;">${estadoIcon}</span>
</td>
</tr>`;
});
$("#aqiTableBody").html(rowsHtml);
let groupsHtml = '';
for (const [category, groups] of Object.entries(data.allGroups)) {
groupsHtml += `
<div style="margin-bottom:20px;">
<h4 style="color:#1e6b52; margin-bottom:10px; border-bottom:1px solid #ddd; padding-bottom:5px;">
${category}
</h4>
<div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(250px, 1fr)); gap:15px;">`;
const uniqueGroups = new Set();
groups.forEach(group => {
const groupKey = `${group.grupo}-${group.recomendacion}`;
if (!uniqueGroups.has(groupKey)) {
uniqueGroups.add(groupKey);
groupsHtml += `
<div style="background:rgba(255,255,255,0.7); padding:15px; border-radius:10px; border-left:3px solid #1e6b52;">
<strong style="color:#1e6b52;">${getEmojiForGroup(group.grupo)} ${group.grupo}</strong><br>
<small>${group.recomendacion}</small>
</div>`;
}
});
groupsHtml += `</div></div>`;
}
$("#dynamicRiskGroups").html(groupsHtml);
}).fail(function(jqXHR, textStatus, errorThrown) {
$('#health-recommendations').html(`
<div style="color:red; padding:20px; background:#ffeeee;">
Error loading air quality data. Please try again later.
<br><small>${textStatus}: ${errorThrown}</small>
</div>
`);
});
});
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString('es-ES', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
});
}
function getLatestContaminantMeasurements(monitoringDataList) {
const contaminantsMap = new Map();
monitoringDataList.forEach(item => {
const contaminantName = item.contaminanteDto.nombre;
const existing = contaminantsMap.get(contaminantName);
if (!existing || new Date(item.fecha) > new Date(existing.fecha)) {
const category = getCategoryForValue(item.valor, window.currentCategories);
contaminantsMap.set(contaminantName, {
...item,
categoriaCalculada: category
});
}
});
return Array.from(contaminantsMap.values());
}
function getCategoryForValue(value, categories) {
const numericValue = Math.floor(Number(value));
const category = categories.find(cat =>
numericValue >= Number(cat.valorMinimo) &&
numericValue <= Number(cat.valorMaximo)
);
return category ? category.categoria : 'Sin categoría';
}
function getCategoryColor(value, categories) {
const category = getCategoryForValue(value, categories);
const index = categories.find(i => i.categoria === category);
return index ? index.color : '#cccccc';
}
function getContaminantPercentage(value, maxLimit) {
return Math.min(100, (value / maxLimit) * 100);
}
function getCategoryMaxLimit(categoryName, categories) {
const category = categories.find(c => c.categoria === categoryName);
return category ? parseFloat(category.valorMaximo) : 100;
}
function getLatestContaminantMeasurements(monitoringDataList) {
const contaminantsMap = new Map();
monitoringDataList.forEach(item => {
const contaminantName = item.contaminanteDto.nombre;
const existing = contaminantsMap.get(contaminantName);
if (!existing || new Date(item.fecha) > new Date(existing.fecha)) {
const category = getCategoryForValue(item.valor, window.currentCategories);
contaminantsMap.set(contaminantName, {
...item,
categoriaCalculada: category
});
}
});
return Array.from(contaminantsMap.values());
}
function createExpressiveCloud(category, color, icaValue) {
let eyeStyle = '';
let mouthStyle = '';
let eyebrowStyle = '';
let blushStyle = '';
let cloudColor = color;
let shadowColor = 'rgba(0,0,0,0.1)';
let animationClass = '';
const faceColor = '#2c3e50';
switch(category.toUpperCase()) {
case 'BUENA':
eyeStyle = `
width: 22px;
height: 22px;
background: ${faceColor};
border-radius: 50%;
position: relative;
`;
eyebrowStyle = `
<div style="position: absolute; top: -10px; left: 0; width: 22px; height: 5px; background: ${faceColor}; border-radius: 2px; transform: rotate(-10deg);"></div>
`;
mouthStyle = `
width: 40px;
height: 20px;
border: 4px solid transparent;
border-bottom: 4px solid ${faceColor};
border-radius: 0 0 40px 40px;
`;
blushStyle = `
<div style="position: absolute; bottom: 20px; left: 10px; width: 18px; height: 9px; background: rgba(255,150,150,0.4); border-radius: 50%;"></div>
<div style="position: absolute; bottom: 20px; right: 10px; width: 18px; height: 9px; background: rgba(255,150,150,0.4); border-radius: 50%;"></div>
`;
cloudColor = color;
animationClass = 'happy-bounce';
break;
case 'REGULAR':
eyeStyle = `
width: 18px;
height: 18px;
background: ${faceColor};
border-radius: 50%;
position: relative;
`;
eyebrowStyle = `
<div style="position: absolute; top: -8px; left: 0; width: 18px; height: 4px; background: ${faceColor}; border-radius: 2px; transform: rotate(10deg);"></div>
`;
mouthStyle = `
width: 30px;
height: 12px;
border: 3px solid transparent;
border-bottom: 3px solid ${faceColor};
border-radius: 0 0 30px 30px;
`;
cloudColor = color;
animationClass = 'neutral-float';
break;
case 'MALA':
eyeStyle = `
width: 20px;
height: 20px;
background: ${faceColor};
border-radius: 50%;
position: relative;
`;
eyebrowStyle = `
<div style="position: absolute; top: -8px; left: 0; width: 20px; height: 4px; background: ${faceColor}; border-radius: 2px;"></div>
`;
mouthStyle = `
width: 35px;
height: 7px;
background: ${faceColor};
border-radius: 3px;
`;
cloudColor = color;
shadowColor = 'rgba(255,152,0,0.2)';
animationClass = 'worried-wiggle';
break;
case 'MUY MALA':
eyeStyle = `
width: 16px;
height: 16px;
background: ${faceColor};
border-radius: 50%;
position: relative;
`;
eyebrowStyle = `
<div style="position: absolute; top: -8px; left: 0; width: 16px; height: 4px; background: ${faceColor}; border-radius: 2px; transform: rotate(15deg);"></div>
`;
mouthStyle = `
width: 32px;
height: 12px;
border: 3px solid transparent;
border-top: 3px solid ${faceColor};
border-radius: 30px 30px 0 0;
`;
blushStyle = `
<div style="position: absolute; bottom: 18px; left: 8px; width: 15px; height: 7px; background: rgba(150,150,255,0.3); border-radius: 50%;"></div>
<div style="position: absolute; bottom: 18px; right: 8px; width: 15px; height: 7px; background: rgba(150,150,255,0.3); border-radius: 50%;"></div>
`;
cloudColor = color;
shadowColor = 'rgba(244,67,54,0.3)';
animationClass = 'sad-wobble';
break;
default:
eyeStyle = `
width: 20px;
height: 20px;
background: ${faceColor};
border-radius: 50%;
position: relative;
`;
eyebrowStyle = `
<div style="position: absolute; top: -8px; left: 0; width: 20px; height: 4px; background: ${faceColor}; border-radius: 2px;"></div>
`;
mouthStyle = `
width: 30px;
height: 5px;
background: ${faceColor};
border-radius: 3px;
`;
cloudColor = color;
}
return `
<div class="expressive-cloud ${animationClass}" style="position:relative; width:100%; height:100%; display:flex; justify-content:center; align-items:center;">
<div class="large-cloud" style="position: relative; width: 250px; height: 180px; display: flex; align-items: center; justify-content: center;">
<div style="position: absolute; z-index: 1; bottom: 20px; left: -10px; width: 100px; height: 80px; background: linear-gradient(145deg, ${lightenColor(cloudColor, 15)}, ${cloudColor}); border-radius: 50%; box-shadow: 5px 5px 20px ${shadowColor};"></div>
<div style="position: absolute; z-index: 2; bottom: 15px; left: 65px; width: 110px; height: 80px; background: linear-gradient(145deg, ${lightenColor(cloudColor, 10)}, ${cloudColor}); border-radius: 50%; box-shadow: 5px 5px 20px ${shadowColor};"></div>
<div style="position: absolute; z-index: 1; bottom: 20px; right: 30px; width: 95px; height: 75px; background: linear-gradient(145deg, ${lightenColor(cloudColor, 15)}, ${cloudColor}); border-radius: 50%; box-shadow: 5px 5px 20px ${shadowColor};"></div>
<div style="position: absolute; z-index: 3; top: 35px; left: 95px; width: 70px; height: 70px; background: linear-gradient(145deg, ${lightenColor(cloudColor, 25)}, ${lightenColor(cloudColor, 10)}); border-radius: 50%; box-shadow: 3px 3px 15px ${shadowColor};"></div>
<div style="position: absolute; z-index: 4; top: 20px; left: 45px; width: 80px; height: 80px; background: linear-gradient(145deg, ${lightenColor(cloudColor, 25)}, ${lightenColor(cloudColor, 10)}); border-radius: 50%; box-shadow: 3px 3px 15px ${shadowColor};"></div>
<div style="position: absolute; z-index: 3; top: 35px; right: 80px; width: 65px; height: 65px; background: linear-gradient(145deg, ${lightenColor(cloudColor, 25)}, ${lightenColor(cloudColor, 10)}); border-radius: 50%; box-shadow: 3px 3px 15px ${shadowColor};"></div>
<div style="position: relative; z-index: 10; margin-top: 20px;">
<!-- Ojos-->
<div style="display: flex; gap: 40px; margin-bottom: 20px; justify-content: center;">
<div style="position: relative;">
<div style="${eyeStyle}">
${eyebrowStyle}
<div style="position: absolute; top: 5px; left: 5px; width: 6px; height: 6px; background: white; border-radius: 50%;"></div>
</div>
</div>
<div style="position: relative;">
<div style="${eyeStyle}">
${eyebrowStyle}
<div style="position: absolute; top: 5px; left: 5px; width: 6px; height: 6px; background: white; border-radius: 50%;"></div>
</div>
</div>
</div>
<!-- Boca -->
<div style="display: flex; justify-content: center;">
<div style="${mouthStyle}"></div>
</div>
<!-- Mejillas sonrojadas -->
${blushStyle}
</div>
</div>
<!-- Badge de categoría -->
<div style="position: absolute;z-index: 20;
bottom: -40px;left: 50%;
transform: translateX(-50%);
background: white;
padding: 10px 25px;
border-radius: 30px;
font-size: 18px;font-weight: bold;
color: ${cloudColor};
box-shadow: 0 6px 18px rgba(0,0,0,0.1);
border: 3px solid ${cloudColor};
text-transform: uppercase;
letter-spacing: 1px;
">
${category}
</div>
<!--
<div style="position: absolute;display: flex;
top: 0px;right: 10px;
background: ${cloudColor};color: white;
width: 65px;height: 65px;
border-radius: 50%;
align-items: center;justify-content: center;
font-weight: bold;font-size: 24px;
box-shadow: 0 6px 18px ${shadowColor};
border: 4px solid white;
">
${Math.round(icaValue)}
</div>-->
</div>
`;
}
function lightenColor(color, percent) {
const num = parseInt(color.replace("#", ""), 16);
const amt = Math.round(2.55 * percent);
const R = (num >> 16) + amt;
const G = (num >> 8 & 0x00FF) + amt;
const B = (num & 0x0000FF) + amt;
return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
(G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
(B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
}
function getContrastColor(hexColor) {
const r = parseInt(hexColor.substr(1, 2), 16);
const g = parseInt(hexColor.substr(3, 2), 16);
const b = parseInt(hexColor.substr(5, 2), 16);
const luminance = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
return luminance > 0.5 ? '#000000' : '#FFFFFF';
}
function getCategoryProgressClass(category) {
switch(category.toUpperCase()) {
case 'BUENA': return 'progress-bar-animated';
case 'REGULAR': return '';
case 'MALA': return 'progress-bar-animated';
case 'MUY MALA': return 'progress-bar-animated progress-bar-striped';
default: return '';
}
}
function getCategoryMaxLimit(category, allCategorias) {
const cat = allCategorias.find(c => c.categoria === category);
return cat ? parseFloat(cat.valor_maximo) : 100;
}
function getPollutantData(callback) {
$.getJSON("data.php", function(mainData) {
const latestDate = mainData.fecha;
$.ajax({
url: "pollutant-data.php",
method: "GET",
data: { date: latestDate },
success: function(pollutantData) {
callback(pollutantData);
},
error: function() {
callback({
pollutants: [
{
nombre: 'ICA',
valor: mainData.ica.valor,
unidad: 'ICA',
categoria: mainData.ica.clasificacion
}
]
});
}
});
});
}
function getContaminantIcon(contaminantName) {
const icons = {
'PM2.5': '🌫️',
'PM10': '💨',
'SO2': '⚗️',
'NO2': '🚗',
'CO': '🔥',
'O3': '☀️',
'NOx': '🏭',
'CO2': '🌡️'
};
return icons[contaminantName] || '🌍';
}
function getEmojiForGroup(groupName) {
const emojis = {
"Personas de la tercera edad": "👴",
"Mujeres embarazadas": "🤱",
"Niños menores de 5 años": "👶",
"Enfermedades respiratorias": "🫁",
"Afecciones cardíacas": "❤️",
"Todos": "👥",
"Respiratorios/Cardiacos": "🫁❤️",
"Adultos mayores": "👵",
"Niños": "🧒"
};
return emojis[groupName] || "👥";
}
</script>
<script>
document.querySelectorAll('td').forEach(cell => {
cell.addEventListener('mouseover', function() {
this.style.backgroundColor = '#e0f2f1';
});
cell.addEventListener('mouseout', function() {
this.style.backgroundColor = '';
});
});
</script>
<script>
document.addEventListener('DOMContentLoaded', () => {
const infoBox = document.getElementById('airInfo');
const buttonsContainer = document.querySelector('.air-buttons');
const scrollContainer = document.createElement('div');
scrollContainer.className = 'air-buttons-container';
buttonsContainer.innerHTML = '';
buttonsContainer.appendChild(scrollContainer);
fetch('data.php')
.then(res => res.json())
.then(data => {
const levels = data.allCategorias;
const currentICA = data.ica;
const idify = str => str.toLowerCase().replace(/\s+/g, '');
levels.forEach(level => {
const levelId = idify(level.categoria);
const isActive = (level.categoria === currentICA.clasificacion);
const btn = document.createElement('button');
btn.className = `air-button ${levelId}` + (isActive ? ' active' : '');
btn.style.cssText = `
color: ${getTextColor(level.color)};
background: linear-gradient(135deg, ${level.color}, ${shadeColor(level.color, 20)});
box-shadow: 0 5px 15px ${hexToRgba(level.color, 0.3)};
${isActive ? 'transform: translateY(-3px);' : ''}
`;
btn.innerHTML = `
${level.categoria}
<small style="display: block; font-size:0.7em; opacity:0.8; margin-top:3px;">
${level.valor_minimo}-${level.valor_maximo}
</small>
`;
btn.onclick = () => showInfo(level);
scrollContainer.appendChild(btn);
});
if (currentICA) {
const currentLevel = levels.find(l => l.categoria === currentICA.clasificacion);
if (currentLevel) showInfo(currentLevel);
}
scrollContainer.querySelectorAll('button').forEach(button => {
button.addEventListener('mouseenter', () => {
button.style.transform = 'translateY(-2px) scale(1.02)';
});
button.addEventListener('mouseleave', () => {
button.style.transform = button.classList.contains('active') ? 'translateY(-3px)' : 'translateY(0) scale(1)';
});
});
function showInfo(level) {
scrollContainer.querySelectorAll('button').forEach(btn => btn.classList.remove('active'));
const id = idify(level.categoria);
const activeBtn = scrollContainer.querySelector(`.air-button.${id}`);
if (activeBtn) activeBtn.classList.add('active');
const recs = [];
if(level.recomendacion) recs.push(level.recomendacion);
const riskGroups = data.allGroups[level.categoria] || [];
infoBox.innerHTML = `
<div style="text-align: left;">
<h3 style="color: ${level.color}; margin-bottom: 10px; font-size: 1.3em; display:flex; align-items:center;">
<span style="display:inline-block; width:20px; height:20px; background:${level.color}; border-radius:50%; margin-right:10px;"></span>
${level.categoria} (${level.valor_minimo}-${level.valor_maximo})
</h3>
<div style="margin-bottom:15px; padding:15px; background:${hexToRgba(level.color, 0.1)}; border-radius:8px;">
<p><strong>Descripción:</strong> ${level.descripcion}</p>
${level.recomendacion ? `<p><strong>Recomendación:</strong> ${level.recomendacion}</p>` : ''}
</div>
${riskGroups.length > 0 ? `
<div style="margin-top:20px;">
<h4 style="color: #1e6b52; font-size: 1.1em; margin-bottom:10px;">Grupos de riesgo:</h4>
<div style="display:grid; gap:10px;">
${riskGroups.map(group => `
<div style="padding:10px; background:#f5f5f5; border-radius:6px; border-left:3px solid ${level.color};">
<div style="font-weight:600;">${group.grupo}</div>
<div style="font-size:0.9em; margin-top:5px;">${group.recomendacion}</div>
</div>
`).join('')}
</div>
</div>` : ''}
</div>
`;
}
function shadeColor(color, percent) {
let f=parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent;
let R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF;
return "#" + (0x1000000 + (Math.round((t-R)*p/100)+R)*0x10000 + (Math.round((t-G)*p/100)+G)*0x100 + (Math.round((t-B)*p/100)+B)).toString(16).slice(1);
}
function hexToRgba(hex, alpha) {
let r = parseInt(hex.slice(1,3),16);
let g = parseInt(hex.slice(3,5),16);
let b = parseInt(hex.slice(5,7),16);
return `rgba(${r},${g},${b},${alpha})`;
}
function getTextColor(bgColor) {
let r = parseInt(bgColor.slice(1,3),16);
let g = parseInt(bgColor.slice(3,5),16);
let b = parseInt(bgColor.slice(5,7),16);
let luminance = 0.299*r + 0.587*g + 0.114*b;
return luminance > 186 ? '#333' : 'white';
}
})
.catch(err => {
console.error('Error fetching AQI data:', err);
document.getElementById('airInfo').innerHTML = '<p>Error cargando datos del índice ICA.</p>';
});
});
</script>
<style>
.large-screen-only { display: block; }
.small-screen-only { display: none; }
.air-buttons-container {
display: flex;
flex-wrap: nowrap;
overflow-x: auto;
gap: 10px;
padding-bottom: 10px;
-webkit-overflow-scrolling: touch;
}
.air-buttons-container::-webkit-scrollbar { display: none; }
.air-button {
position: relative;
border: none;
border-radius: 12px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
text-transform: uppercase;
letter-spacing: 1px;
backdrop-filter: blur(10px);
margin: 5px;
text-align: center;
flex: 0 0 auto;
min-width: 150px;
white-space: nowrap;
padding: 15px 20px;
font-size: 0.9em;
}
.air-button:hover {
transform: translateY(-3px);
box-shadow: 0 8px 20px rgba(0,0,0,0.2) !important;
}
.air-button.active {
transform: translateY(-3px);
box-shadow: 0 8px 25px rgba(0,0,0,0.3) !important;
}
.info-box {
background: rgba(255,255,255,0.95);
backdrop-filter: blur(20px);
border-radius: 20px;
padding: 20px;
margin: 20px auto;
max-width: 100%;
border: 1px solid rgba(255,255,255,0.3);
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}
#aqiTable {
width: 100%;
border-collapse: collapse;
font-size: 16px;
background: white;
display: table;
}
/* Cloud animations */
@keyframes happy-bounce {
0%, 100% { transform: translateY(0px) scale(1); }
50% { transform: translateY(-10px) scale(1.05); }
}
@keyframes neutral-float {
0%, 100% { transform: translateY(0px); }
50% { transform: translateY(-5px); }
}
@keyframes worried-wiggle {
0%, 100% { transform: rotate(0deg); }
25% { transform: rotate(-2deg); }
75% { transform: rotate(2deg); }
}
@keyframes sad-wobble {
0%, 100% { transform: translateY(0px) rotate(0deg); }
50% { transform: translateY(5px) rotate(-2deg); }
}
.happy-bounce {
animation: happy-bounce 3s ease-in-out infinite;
}
.neutral-float {
animation: neutral-float 4s ease-in-out infinite;
}
.worried-wiggle {
animation: worried-wiggle 2.5s ease-in-out infinite;
}
.sad-wobble {
animation: sad-wobble 4s ease-in-out infinite;
}
/* Progress bar animations */
.progress-bar-animated {
animation: progress-bar-stripes 1s linear infinite;
}
@keyframes progress-bar-stripes {
0% { background-position: 1rem 0; }
100% { background-position: 0 0; }
}
.progress-bar-striped {
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-size: 1rem 1rem;
}
/* Risk Groups Scroller */
.risk-groups-container {
position: relative;
}
.risk-groups-scroller {
overflow-x: auto;
scroll-behavior: smooth;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
margin: 0 -5px;
padding: 0 5px;
}
.risk-groups-scroller::-webkit-scrollbar {
display: none;
}
.risk-groups-wrapper {
display: flex;
gap: 10px;
padding-bottom: 10px;
}
.risk-group-card {
flex: 0 0 calc(90% - 10px);
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
border-left: 4px solid #F44336;
}
.scroll-arrows {
display: flex;
gap: 5px;
}
.scroll-arrows button {
background: #f0f0f0;
border: none;
width: 24px;
height: 24px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s;
}
.scroll-arrows button:hover {
background: #1e6b52;
color: white;
}
@media (min-width: 768px) {
.risk-group-card {
flex: 0 0 calc(50% - 10px);
}
}
@media (min-width: 992px) {
.risk-group-card {
flex: 0 0 calc(33% - 10px);
}
}
@media (max-width: 768px) {
.interactive-air-quality { padding: 80px 20px !important; }
.column.mcb-column.one-third { width: 100% !important; margin-bottom: 20px; }
#aqi-cloud-container {
width: 120px !important;
height: 120px !important;
}
}
@media (max-width: 480px) {
#aqi-cloud-container {
width: 150px !important;
height: 100px !important;
}
}
.pollutant-level {
background: rgba(255, 255, 255, 0.8);
padding: 15px;
border-radius: 10px;
margin-bottom: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.pollutant-value {
font-size: 18px;
font-weight: bold;
}
/* Risk groups styling */
.risk-group-card {
flex: 0 0 calc(90% - 10px);
background: white;
padding: 18px;
border-radius: 10px;
box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
border-left: 4px solid #1e6b52;
}
/* Card styling */
.air-quality-card {
box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1);
border-radius: 12px;
padding: 25px;
}
/* Responsive improvements */
@media (max-width: 768px) {
.pollutant-value {
font-size: 16px;
padding: 3px 10px;
}
.risk-group-card {
flex: 0 0 calc(95% - 10px);
padding: 15px;
}
}
/* Progress bar animations */
@keyframes progress-pulse {
0% { opacity: 1; }
50% { opacity: 0.7; }
100% { opacity: 1; }
}
.progress-bar-animated {
animation: progress-pulse 2s infinite;
}
.expressive-cloud {
transition: all 0.5s ease;
}
.expressive-cloud:hover {
transform: scale(1.05);
transition: transform 0.3s ease;
}
</style>
</body>
</html>