diff --git a/README.md b/README.md new file mode 100644 index 0000000..a23a49c --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# Weather App + +Приложение для просмотра погоды. + +## Описание + +Это веб-приложение, которое отображает текущую погоду и почасовой прогноз с использованием API WeatherAPI.com. Интерфейс построен на Tailwind CSS для современного дизайна. + +## Функциональность + +- Отображение текущей погоды (температура, влажность, ветер) +- Таймлапс погоды на день +- Адаптивный дизайн +- Выбор городов + +## Технологии + +- Node.js +- Express +- Tailwind CSS +- HTML5 +- JavaScript +- Swiper.js (для слайдера) +- Chart.js (для графиков) +- Lucide Icons (для иконок) +- Google Fonts (Inter) + +## Установка + +1. Клонируйте репозиторий: + ```bash + git clone + cd weather-app + ``` + +2. Установите зависимости: + ```bash + npm install + ``` + +3. Запустите сервер: + ```bash + npm start + ``` + +4. Откройте http://localhost:3000 в браузере. + +## Структура проекта + +- `server.js` - сервер на Express +- `index.html` - главная страница +- `script.js` - клиентский JavaScript +- `package.json` - конфигурация + +## Лицензия + +MIT \ No newline at end of file diff --git a/index.html b/index.html index 18f0281..78c0959 100644 --- a/index.html +++ b/index.html @@ -4,29 +4,198 @@ Погода - - + + + + + + + + + - -
-
-

Погода

+ +
+ +
+
+
+ +
+

Погода

+
+

Узнайте погоду в вашем городе

+
+ + Загрузка... +
-
- - - + + +
+
+
+ + +
+ + +
+ +
-
-

Таймлапс погоды

-
+ + + + +
+

+ + Погода на весь день +

+
+
+
+
+ + +
+

+ + Погода на неделю +

+
+ +
+
+ + +
+

+ + Графики погоды +

+
+ +
+

+ + Температура (°C) +

+ +
+ + +
+

+ + Осадки (мм) +

+ +
+
+ + + + + + + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7f3a589..bf965cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,9 @@ "dependencies": { "express": "^4.17.1" }, + "devDependencies": { + "tailwindcss": "^4.1.14" + }, "engines": { "node": "8" } @@ -718,6 +721,12 @@ "node": ">= 0.8" } }, + "node_modules/tailwindcss": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", + "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==", + "dev": true + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", diff --git a/package.json b/package.json index e7f9d95..00da365 100644 --- a/package.json +++ b/package.json @@ -11,5 +11,8 @@ }, "dependencies": { "express": "^4.17.1" + }, + "devDependencies": { + "tailwindcss": "^4.1.14" } -} \ No newline at end of file +} diff --git a/script.js b/script.js index 61c2d46..adc3a5e 100644 --- a/script.js +++ b/script.js @@ -1,25 +1,118 @@ // API ключ от WeatherAPI const API_KEY = '485eff906f7d473b913104046250710'; - const citySelect = document.getElementById('city'); const getWeatherBtn = document.getElementById('get-weather'); const timelapseContainer = document.getElementById('timelapse-container'); +const currentWeatherDiv = document.getElementById('current-weather'); +const currentTempEl = document.getElementById('current-temp'); +const currentDescEl = document.getElementById('current-desc'); +const currentHumidityEl = document.getElementById('current-humidity'); +const currentWindEl = document.getElementById('current-wind'); -// Добавляем скроллинг колесиком мыши для таймлапса -timelapseContainer.addEventListener('wheel', (event) => { - event.preventDefault(); - timelapseContainer.scrollLeft += event.deltaY; -}); +// Глобальная переменная для Swiper +let weatherSwiper; + +// Глобальные переменные для графиков +let temperatureChart = null; +let precipitationChart = null; + +// Иконки погоды +const weatherIcons = { + 'Sunny': 'sun', + 'Clear': 'sun', + 'Partly cloudy': 'cloud-sun', + 'Cloudy': 'cloud', + 'Overcast': 'cloud', + 'Mist': 'cloud-fog', + 'Fog': 'cloud-fog', + 'Light rain': 'cloud-rain', + 'Moderate rain': 'cloud-rain', + 'Heavy rain': 'cloud-rain', + 'Light snow': 'cloud-snow', + 'Moderate snow': 'cloud-snow', + 'Heavy snow': 'cloud-snow', + 'Thunderstorm': 'cloud-lightning', + 'Patchy rain possible': 'cloud-drizzle', + 'Patchy snow possible': 'cloud-snow', + 'Patchy sleet possible': 'cloud-snow', + 'Patchy freezing drizzle possible': 'cloud-drizzle', + 'Blowing snow': 'wind', + 'Blizzard': 'wind', + 'Freezing fog': 'cloud-fog', + 'Patchy light drizzle': 'cloud-drizzle', + 'Light drizzle': 'cloud-drizzle', + 'Freezing drizzle': 'cloud-drizzle', + 'Heavy freezing drizzle': 'cloud-drizzle', + 'Patchy light rain': 'cloud-rain', + 'Light rain shower': 'cloud-rain', + 'Moderate or heavy rain shower': 'cloud-rain', + 'Torrential rain shower': 'cloud-rain', + 'Patchy light snow': 'cloud-snow', + 'Light snow showers': 'cloud-snow', + 'Moderate or heavy snow showers': 'cloud-snow', + 'Patchy light rain with thunder': 'cloud-lightning', + 'Moderate or heavy rain with thunder': 'cloud-lightning', + 'Patchy light snow with thunder': 'cloud-lightning', + 'Moderate or heavy snow with thunder': 'cloud-lightning' +}; + +// Функция для отображения текущей даты +function displayCurrentDate() { + const currentDateEl = document.getElementById('current-date'); + const now = new Date(); + + const daysOfWeek = ['воскресенье', 'понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота']; + const months = ['января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря']; + + const dayOfWeek = daysOfWeek[now.getDay()]; + const day = now.getDate(); + const month = months[now.getMonth()]; + + currentDateEl.textContent = `${dayOfWeek}, ${day} ${month}`; +} + +// Функция для обновления заголовка страницы +function updatePageTitle() { + const selectedCity = citySelect.options[citySelect.selectedIndex].text; + document.title = `Погода в ${selectedCity}`; +} // Автоматическая загрузка погоды при загрузке страницы -window.addEventListener('load', () => { - getWeatherBtn.click(); +document.addEventListener('DOMContentLoaded', () => { + // Отображаем текущую дату + displayCurrentDate(); + + // Загружаем сохраненный город из localStorage + const savedCity = localStorage.getItem('selectedCity'); + if (savedCity) { + citySelect.value = savedCity; + } + + // Обновляем заголовок страницы + updatePageTitle(); + + // Ждем загрузки Swiper + if (typeof Swiper !== 'undefined') { + getWeatherBtn.click(); + } else { + // Если Swiper еще не загрузился, ждем его + const checkSwiper = setInterval(() => { + if (typeof Swiper !== 'undefined') { + clearInterval(checkSwiper); + getWeatherBtn.click(); + } + }, 100); + } }); getWeatherBtn.addEventListener('click', async () => { const city = citySelect.value; - const url = `https://api.weatherapi.com/v1/forecast.json?key=${API_KEY}&q=${city}&days=1&hourly=true&lang=ru`; + + // Сохраняем выбранный город в localStorage + localStorage.setItem('selectedCity', city); + + const url = `https://api.weatherapi.com/v1/forecast.json?key=${API_KEY}&q=${city}&days=7&hourly=true&lang=ru`; try { const response = await fetch(url); @@ -27,35 +120,424 @@ getWeatherBtn.addEventListener('click', async () => { throw new Error('Ошибка сети'); } const data = await response.json(); - displayTimelapse(data.forecast.forecastday[0].hour); // Таймлапс на сегодня + + // Отображаем текущую погоду + displayCurrentWeather(data); + + // Пересоздаем иконки после обновления DOM + setTimeout(() => { + lucide.createIcons(); + }, 100); + + // Таймлапс на сегодня + displayTimelapse(data.forecast.forecastday[0].hour, data.location.localtime); + + // Погода на неделю + displayWeeklyWeather(data.forecast.forecastday); + + // Графики температуры и осадков + createTemperatureChart(data.forecast.forecastday[0].hour); + createPrecipitationChart(data.forecast.forecastday[0].hour); + + // Обновляем заголовок страницы с выбранным городом + updatePageTitle(); } catch (error) { console.error('Ошибка загрузки данных:', error); alert('Не удалось загрузить данные о погоде. Проверьте API ключ.'); } }); -function displayTimelapse(hourlyData) { +function displayCurrentWeather(data) { + const current = data.current; + currentTempEl.textContent = `${Math.round(current.temp_c)}°C`; + currentDescEl.textContent = current.condition.text; + currentHumidityEl.textContent = `${current.humidity}%`; + currentWindEl.textContent = `${current.wind_kph} км/ч`; + + // Показываем блок текущей погоды + currentWeatherDiv.classList.remove('hidden'); + currentWeatherDiv.classList.add('animate-fade-in'); +} + +function displayTimelapse(hourlyData, localtime) { timelapseContainer.innerHTML = ''; - hourlyData.forEach(item => { - const div = document.createElement('div'); - div.className = 'timelapse-item'; + const currentHour = new Date(localtime).getHours(); + let currentSlideIndex = -1; + + hourlyData.forEach((item, index) => { + const slide = document.createElement('div'); const hour = new Date(item.time).getHours(); - div.innerHTML = ` -

${hour}:00

-

${Math.round(item.temp_c)}°C

-

${item.condition.text}

-

Осадки: ${item.precip_mm} мм (${item.chance_of_rain}%)

+ const isCurrent = hour === currentHour; + if (isCurrent) currentSlideIndex = index; + + slide.className = `swiper-slide timelapse-item bg-gradient-to-br from-blue-50 to-indigo-50 p-3 rounded-xl shadow-md border ${isCurrent ? 'border-blue-500 bg-gradient-to-br from-blue-100 to-indigo-100 ring-2 ring-blue-300' : 'border-gray-100'}`; + slide.style.width = '140px'; + const iconName = weatherIcons[item.condition.text] || 'cloud'; + slide.innerHTML = ` +
+

${hour}:00 ${isCurrent ? '(сейчас)' : ''}

+
+ +
+

${Math.round(item.temp_c)}°C

+

${item.condition.text}

+

💧 ${item.precip_mm} мм

+

☔ ${item.chance_of_rain}%

+
`; - timelapseContainer.appendChild(div); + timelapseContainer.appendChild(slide); }); - // Фокус на текущем времени - const currentHour = new Date().getHours(); - const currentDiv = Array.from(timelapseContainer.children).find(div => { - const h3 = div.querySelector('h3'); - return parseInt(h3.textContent) === currentHour; - }); - if (currentDiv) { - currentDiv.scrollIntoView({ behavior: 'smooth', inline: 'center' }); - } + // Пересоздаем иконки + setTimeout(() => { + lucide.createIcons(); + }, 100); + + // Инициализируем Swiper если он еще не создан + setTimeout(() => { + if (!weatherSwiper) { + weatherSwiper = new Swiper('.swiper', { + slidesPerView: window.innerWidth < 768 ? 3 : 6, + spaceBetween: 12, + grabCursor: true, + freeMode: true, + mousewheel: { + enabled: true, + sensitivity: 1, + }, + slidesOffsetBefore: 0, + slidesOffsetAfter: 0, + centeredSlides: false, + watchSlidesProgress: true + }); + } else { + weatherSwiper.update(); + weatherSwiper.updateSlides(); + } + + // Фокус на текущем времени города + if (currentSlideIndex !== -1) { + setTimeout(() => { + weatherSwiper.slideTo(currentSlideIndex, 800); + }, 200); + } + }, 50); +} + +function displayWeeklyWeather(forecastData) { + const weeklyContainer = document.getElementById('weekly-container'); + weeklyContainer.innerHTML = ''; + + const daysOfWeek = ['вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб']; + + forecastData.forEach((day, index) => { + const date = new Date(day.date); + const dayOfWeek = daysOfWeek[date.getDay()]; + const dayNumber = date.getDate(); + const month = date.toLocaleDateString('ru-RU', { month: 'short' }); + + const iconName = weatherIcons[day.day.condition.text] || 'cloud'; + const isToday = index === 0; + + const card = document.createElement('div'); + card.className = `text-center p-4 rounded-xl border transition-all duration-200 hover:shadow-lg ${ + isToday + ? 'bg-blue-50 border-blue-300 ring-2 ring-blue-200' + : 'bg-gray-50 border-gray-200 hover:border-blue-300' + }`; + + card.innerHTML = ` +
+

+ ${isToday ? 'Сегодня' : dayOfWeek} +

+

${dayNumber} ${month}

+
+
+ +
+
+

+ ${Math.round(day.day.maxtemp_c)}° +

+

+ ${Math.round(day.day.mintemp_c)}° +

+
+

+ ${day.day.condition.text} +

+ `; + + weeklyContainer.appendChild(card); + }); + + // Пересоздаем иконки для недельного прогноза + setTimeout(() => { + lucide.createIcons(); + }, 100); +} + +// Функция создания графика температуры +function createTemperatureChart(hourlyData) { + const ctx = document.getElementById('temperatureChart').getContext('2d'); + + // Подготавливаем данные + const labels = hourlyData.map(item => { + const hour = new Date(item.time).getHours(); + return `${hour}:00`; + }); + + const temperatures = hourlyData.map(item => Math.round(item.temp_c)); + + // Уничтожаем предыдущий график если он существует + if (temperatureChart) { + temperatureChart.destroy(); + } + + // Создаем новый график + temperatureChart = new Chart(ctx, { + type: 'line', + data: { + labels: labels, + datasets: [{ + label: 'Температура (°C)', + data: temperatures, + borderColor: '#3b82f6', + backgroundColor: 'rgba(59, 130, 246, 0.1)', + borderWidth: 3, + fill: true, + tension: 0.4, + pointBackgroundColor: '#3b82f6', + pointBorderColor: '#ffffff', + pointBorderWidth: 2, + pointRadius: 4, + pointHoverRadius: 6, + pointHoverBackgroundColor: '#2563eb', + pointHoverBorderColor: '#ffffff', + pointHoverBorderWidth: 2 + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + display: false + }, + tooltip: { + backgroundColor: 'rgba(0, 0, 0, 0.8)', + titleColor: '#ffffff', + bodyColor: '#ffffff', + cornerRadius: 8, + displayColors: false, + callbacks: { + title: function(context) { + return `Время: ${context[0].label}`; + }, + label: function(context) { + return `Температура: ${context.parsed.y}°C`; + } + } + } + }, + scales: { + x: { + grid: { + display: false + }, + ticks: { + color: '#6b7280', + font: { + size: 12 + } + } + }, + y: { + grid: { + color: 'rgba(0, 0, 0, 0.1)', + lineWidth: 1 + }, + ticks: { + color: '#6b7280', + font: { + size: 12 + }, + callback: function(value) { + return value + '°C'; + } + } + } + }, + animation: { + duration: 2000, + easing: 'easeInOutQuart' + }, + interaction: { + intersect: false, + mode: 'index' + } + } + }); +} + +// Функция создания графика осадков +function createPrecipitationChart(hourlyData) { + const ctx = document.getElementById('precipitationChart').getContext('2d'); + + // Подготавливаем данные + const labels = hourlyData.map(item => { + const hour = new Date(item.time).getHours(); + return `${hour}:00`; + }); + + const precipitations = hourlyData.map(item => item.precip_mm); + const chances = hourlyData.map(item => item.chance_of_rain); + + // Уничтожаем предыдущий график если он существует + if (precipitationChart) { + precipitationChart.destroy(); + } + + // Создаем новый график + precipitationChart = new Chart(ctx, { + type: 'bar', + data: { + labels: labels, + datasets: [{ + label: 'Осадки (мм)', + data: precipitations, + backgroundColor: 'rgba(59, 130, 246, 0.6)', + borderColor: '#3b82f6', + borderWidth: 1, + borderRadius: 4, + borderSkipped: false, + barThickness: 'flex', + maxBarThickness: 30 + }, { + label: 'Вероятность (%)', + data: chances, + type: 'line', + borderColor: '#ef4444', + backgroundColor: 'rgba(239, 68, 68, 0.1)', + borderWidth: 2, + fill: false, + tension: 0.4, + pointBackgroundColor: '#ef4444', + pointBorderColor: '#ffffff', + pointBorderWidth: 2, + pointRadius: 3, + pointHoverRadius: 5, + pointHoverBackgroundColor: '#dc2626', + pointHoverBorderColor: '#ffffff', + pointHoverBorderWidth: 2, + yAxisID: 'y1' + }] + }, + options: { + responsive: true, + maintainAspectRatio: false, + plugins: { + legend: { + display: false + }, + tooltip: { + backgroundColor: 'rgba(0, 0, 0, 0.8)', + titleColor: '#ffffff', + bodyColor: '#ffffff', + cornerRadius: 8, + displayColors: true, + callbacks: { + title: function(context) { + return `Время: ${context[0].label}`; + }, + label: function(context) { + if (context.datasetIndex === 0) { + return `Осадки: ${context.parsed.y} мм`; + } else { + return `Вероятность: ${context.parsed.y}%`; + } + } + } + } + }, + scales: { + x: { + grid: { + display: false + }, + ticks: { + color: '#6b7280', + font: { + size: 12 + } + } + }, + y: { + type: 'linear', + display: true, + position: 'left', + grid: { + color: 'rgba(0, 0, 0, 0.1)', + lineWidth: 1 + }, + ticks: { + color: '#6b7280', + font: { + size: 12 + }, + callback: function(value) { + return value + ' мм'; + } + }, + title: { + display: true, + text: 'Осадки (мм)', + color: '#3b82f6', + font: { + size: 14, + weight: 'bold' + } + } + }, + y1: { + type: 'linear', + display: true, + position: 'right', + grid: { + drawOnChartArea: false + }, + ticks: { + color: '#ef4444', + font: { + size: 12 + }, + callback: function(value) { + return value + '%'; + } + }, + title: { + display: true, + text: 'Вероятность (%)', + color: '#ef4444', + font: { + size: 14, + weight: 'bold' + } + } + } + }, + animation: { + duration: 2000, + easing: 'easeInOutQuart', + delay: function(context) { + return context.dataIndex * 100; + } + }, + interaction: { + intersect: false, + mode: 'index' + } + } + }); } diff --git a/server.js b/server.js index e00feea..c0e7360 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,6 @@ const express = require('express'); const app = express(); -const port = 3000; +const port = process.env.PORT || 3000; // Обслуживание статических файлов app.use(express.static('.')); diff --git a/style.css b/style.css deleted file mode 100644 index 1ece68f..0000000 --- a/style.css +++ /dev/null @@ -1,293 +0,0 @@ -body { - font-family: 'Inter', sans-serif; - background-color: #f8f9fb; - color: #333; - margin: 0; - padding: 20px; - line-height: 1.6; -} - -.container { - max-width: 1400px; - margin: 0 auto; - background-color: white; - border-radius: 16px; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); - padding: 40px; -} - -header { - text-align: center; - margin-bottom: 40px; -} - -h1 { - font-size: 2.5rem; - font-weight: 600; - color: #333; - margin: 0; -} - -.city-selector { - display: flex; - flex-direction: column; - align-items: center; - margin-bottom: 40px; - padding: 24px; - background-color: #eef0f4; - border-radius: 12px; -} - -label { - font-weight: 500; - margin-bottom: 10px; - color: #555; -} - -select { - padding: 12px 16px; - border: 1px solid #ddd; - border-radius: 8px; - font-size: 1rem; - background-color: white; - margin-bottom: 15px; - min-width: 200px; -} - -button { - padding: 12px 24px; - background-color: #3b82f6; - color: white; - border: none; - border-radius: 8px; - font-size: 1rem; - font-weight: 500; - cursor: pointer; - transition: background-color 0.3s ease; -} - -button:hover { - background-color: #2563eb; -} - -.weather-info { - display: flex; - flex-direction: column; - gap: 40px; -} - -.timelapse-container { - display: flex; - flex-direction: row; - overflow-x: scroll; - padding: 10px 0; - scrollbar-width: thin; - scrollbar-color: #ccc transparent; -} - -.timelapse-item { - flex-shrink: 0; - width: 140px; - margin-right: 15px; - background-color: #eef0f4; - padding: 20px; - border-radius: 12px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - text-align: center; - transition: transform 0.2s ease; -} - -.timelapse-item:hover { - transform: translateY(-2px); -} - -.timelapse-item h3 { - margin: 0 0 8px 0; - font-size: 1.1rem; - font-weight: 600; - color: #333; -} - -.timelapse-item p { - margin: 4px 0; - font-size: 0.9rem; - color: #666; -} - -.timelapse-item .temp { - font-size: 1.2rem; - font-weight: 500; - color: #3b82f6; -} - -.timelapse-item .desc { - font-weight: 500; -} - -.timelapse-item .prec { - margin: 4px 0; - font-size: 0.8rem; - color: #777; -} - -.weather-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); - gap: 20px; -} - -.weather-item { - background-color: #eef0f4; - padding: 16px; - border-radius: 12px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - text-align: center; - transition: transform 0.2s ease; -} - -.weather-item:hover { - transform: translateY(-2px); -} - -.weather-item h3 { - margin: 0 0 8px 0; - font-size: 1.1rem; - font-weight: 600; - color: #333; -} - -.weather-item p { - margin: 4px 0; - font-size: 0.9rem; - color: #666; -} - -.weather-item .temp { - font-size: 1.2rem; - font-weight: 500; - color: #3b82f6; -} - -.weather-item .desc { - font-weight: 500; -} - -/* Медиа-запросы для адаптивности */ - -/* Планшеты и небольшие десктопы */ -@media (min-width: 768px) { - .weather-info { - flex-direction: row; - } - - .hourly-weather, .daily-weather { - flex: 1; - } - - .container { - padding: 50px; - } - - h1 { - font-size: 3rem; - } -} - -/* Большие экраны */ -@media (min-width: 1200px) { - .container { - max-width: 1600px; - padding: 60px; - } - - .timelapse-item { - width: 160px; - margin-right: 20px; - padding: 24px; - } - - h1 { - font-size: 3.5rem; - } - - .timelapse-item h3 { - font-size: 1.2rem; - } - - .timelapse-item .temp { - font-size: 1.4rem; - } -} - -/* Сверхбольшие экраны */ -@media (min-width: 1440px) { - .container { - max-width: 1800px; - padding: 80px; - } - - .timelapse-item { - width: 180px; - margin-right: 25px; - padding: 28px; - } - - h1 { - font-size: 4rem; - } - - .timelapse-item h3 { - font-size: 1.3rem; - margin-bottom: 12px; - } - - .timelapse-item .temp { - font-size: 1.6rem; - margin: 8px 0; - } - - .timelapse-item .desc { - font-size: 1rem; - margin: 6px 0; - } - - .timelapse-item .prec { - font-size: 0.9rem; - margin: 6px 0; - } -} - -/* Ультра-широкие экраны */ -@media (min-width: 1920px) { - .container { - max-width: 2200px; - padding: 100px; - } - - .timelapse-item { - width: 200px; - margin-right: 30px; - padding: 32px; - } - - h1 { - font-size: 4.5rem; - } - - .city-selector { - padding: 30px; - margin-bottom: 50px; - } - - select { - padding: 16px 20px; - font-size: 1.1rem; - min-width: 250px; - margin-bottom: 20px; - } - - button { - padding: 16px 32px; - font-size: 1.1rem; - } -} \ No newline at end of file