CSS
/* ─── 10 Sky Widgets — sky mist weather dashboard ─────────────────── */
@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;500;600;700;800;900&family=Space+Mono:wght@400;700&display=swap');
.nm-sky {
--nm-sky-bg: #e8f0f8;
--nm-sky-sd: #c4ccd8;
--nm-sky-sl: #f8fdff;
--nm-sky-ib: #dce5f0;
--nm-sky-sun: #f6c94e;
--nm-sky-sky: #5b9ec9;
--nm-sky-sky2:#3a7ea8;
--nm-sky-warm:#e07b50;
--nm-sky-mnt: #78bda8;
--nm-sky-txt: #6a7a8a;
--nm-sky-txt2:#1a2a38;
--nm-sky-r: 22px;
--nm-sky-neu: 10px 10px 24px var(--nm-sky-sd), -10px -10px 24px var(--nm-sky-sl);
--nm-sky-neu-sm: 6px 6px 14px var(--nm-sky-sd), -6px -6px 14px var(--nm-sky-sl);
--nm-sky-neu-sm-in: inset 5px 5px 10px var(--nm-sky-sd), inset -5px -5px 10px var(--nm-sky-sl);
position: relative;
width: 100%;
min-height: 900px;
background: var(--nm-sky-bg);
font-family: 'Nunito', system-ui, sans-serif;
color: var(--nm-sky-txt);
display: flex;
align-items: center;
justify-content: center;
padding: 32px 16px;
overflow: hidden;
box-sizing: border-box;
}
.nm-sky *,
.nm-sky *::before,
.nm-sky *::after { box-sizing: border-box; }
.nm-sky .card {
position: relative;
width: 100%;
max-width: 860px;
background: var(--nm-sky-bg);
border-radius: 40px;
padding: 24px;
box-shadow: 24px 24px 58px var(--nm-sky-sd), -24px -24px 58px var(--nm-sky-sl);
display: grid;
grid-template-columns: 340px 1fr 1fr;
grid-template-rows: auto auto auto;
gap: 18px;
}
.nm-sky .widget {
background: var(--nm-sky-bg);
border-radius: var(--nm-sky-r);
box-shadow: var(--nm-sky-neu);
padding: 22px;
position: relative;
overflow: hidden;
}
.nm-sky .widget::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 60%;
height: 40%;
background: radial-gradient(ellipse, rgba(255, 255, 255, 0.3) 0%, transparent 70%);
border-radius: 50%;
pointer-events: none;
}
/* Widget 1 — Main */
.nm-sky .w-main {
grid-column: 1;
grid-row: 1 / 3;
padding: 26px 24px;
display: flex;
flex-direction: column;
gap: 18px;
}
.nm-sky .city-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.nm-sky .city-name {
font-size: 22px;
font-weight: 800;
color: var(--nm-sky-txt2);
letter-spacing: -0.5px;
}
.nm-sky .city-country {
font-size: 12px;
color: var(--nm-sky-txt);
font-weight: 500;
margin-top: 2px;
}
.nm-sky .live-dot {
display: flex;
align-items: center;
gap: 6px;
font-size: 10px;
font-weight: 700;
letter-spacing: 1.5px;
text-transform: uppercase;
color: var(--nm-sky-mnt);
}
.nm-sky .dot-pulse {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--nm-sky-mnt);
animation: nm-sky-pulse 2s ease-in-out infinite;
}
@keyframes nm-sky-pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(120, 189, 168, 0.5); }
50% { box-shadow: 0 0 0 8px rgba(120, 189, 168, 0); }
}
.nm-sky .temp-block {
display: flex;
align-items: center;
gap: 16px;
}
.nm-sky .weather-icon-wrap {
width: 80px;
height: 80px;
border-radius: 50%;
background: var(--nm-sky-bg);
box-shadow: var(--nm-sky-neu-sm);
display: inline-flex;
align-items: center;
justify-content: center;
position: relative;
flex-shrink: 0;
}
.nm-sky .weather-icon-wrap::after {
content: '';
position: absolute;
inset: 8px;
border-radius: 50%;
background: var(--nm-sky-ib);
box-shadow: var(--nm-sky-neu-sm-in);
}
.nm-sky .weather-emoji {
font-size: 32px;
position: relative;
z-index: 2;
animation: nm-sky-float 3s ease-in-out infinite;
}
@keyframes nm-sky-float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
.nm-sky .temp-value {
font-family: 'Space Mono', ui-monospace, monospace;
font-size: 58px;
font-weight: 700;
color: var(--nm-sky-txt2);
line-height: 1;
letter-spacing: -3px;
}
.nm-sky .temp-deg { font-size: 26px; color: var(--nm-sky-sky); }
.nm-sky .temp-cond {
font-size: 15px;
font-weight: 700;
color: var(--nm-sky-txt2);
margin-top: 2px;
}
.nm-sky .temp-feel {
font-size: 11px;
color: var(--nm-sky-txt);
margin-top: 4px;
font-weight: 500;
}
.nm-sky .stats-strip {
display: flex;
background: var(--nm-sky-ib);
border-radius: 16px;
box-shadow: var(--nm-sky-neu-sm-in);
overflow: hidden;
}
.nm-sky .stat-cell {
flex: 1;
padding: 14px 8px;
text-align: center;
border-right: 1px solid rgba(150, 170, 190, 0.2);
}
.nm-sky .stat-cell:last-child { border-right: none; }
.nm-sky .stat-icon { font-size: 16px; margin-bottom: 5px; }
.nm-sky .stat-val {
font-family: 'Space Mono', ui-monospace, monospace;
font-size: 13px;
font-weight: 700;
color: var(--nm-sky-txt2);
}
.nm-sky .stat-nm {
font-size: 9px;
color: var(--nm-sky-txt);
text-transform: uppercase;
letter-spacing: 1px;
margin-top: 2px;
}
.nm-sky .forecast-row { display: flex; gap: 6px; }
.nm-sky .fc-day {
flex: 1;
background: var(--nm-sky-bg);
border-radius: 14px;
box-shadow: var(--nm-sky-neu-sm);
padding: 10px 4px;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
cursor: pointer;
transition: all 0.2s;
}
.nm-sky .fc-day:hover {
box-shadow: 8px 8px 18px var(--nm-sky-sd), -8px -8px 18px var(--nm-sky-sl);
transform: translateY(-2px);
}
.nm-sky .fc-day.today { box-shadow: var(--nm-sky-neu-sm-in); }
.nm-sky .fc-day-name {
font-size: 9px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--nm-sky-txt);
}
.nm-sky .fc-icon { font-size: 16px; }
.nm-sky .fc-hi { font-size: 12px; font-weight: 800; color: var(--nm-sky-txt2); }
.nm-sky .fc-lo { font-size: 10px; color: var(--nm-sky-txt); }
.nm-sky .fc-day.today .fc-day-name { color: var(--nm-sky-sky); }
.nm-sky .fc-bar-wrap {
width: 4px;
height: 24px;
background: var(--nm-sky-ib);
border-radius: 2px;
box-shadow: inset 1px 1px 3px var(--nm-sky-sd), inset -1px -1px 3px var(--nm-sky-sl);
position: relative;
}
.nm-sky .fc-bar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
border-radius: 2px;
background: linear-gradient(to top, var(--nm-sky-sky2), var(--nm-sky-sky));
}
.nm-sky .fc-day.today .fc-bar { background: linear-gradient(to top, var(--nm-sky-sky2), var(--nm-sky-sun)); }
/* Widget 2 — Clock */
.nm-sky .w-clock {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
padding: 24px 18px;
}
.nm-sky .clock-display {
background: var(--nm-sky-ib);
border-radius: 18px;
padding: 16px 20px;
box-shadow: var(--nm-sky-neu-sm-in);
text-align: center;
}
.nm-sky .clock-time {
font-family: 'Space Mono', ui-monospace, monospace;
font-size: 32px;
font-weight: 700;
color: var(--nm-sky-txt2);
letter-spacing: -1px;
line-height: 1;
}
.nm-sky .clock-sec { color: var(--nm-sky-sky); }
.nm-sky .clock-date {
font-size: 11px;
font-weight: 600;
color: var(--nm-sky-txt);
margin-top: 6px;
letter-spacing: 0.3px;
}
.nm-sky .clock-ampm {
font-family: 'Space Mono', ui-monospace, monospace;
font-size: 11px;
font-weight: 700;
color: var(--nm-sky-sky);
letter-spacing: 2px;
text-transform: uppercase;
}
.nm-sky .analog-wrap { position: relative; width: 76px; height: 76px; }
.nm-sky .analog-face {
width: 76px;
height: 76px;
border-radius: 50%;
background: var(--nm-sky-bg);
box-shadow: var(--nm-sky-neu-sm);
position: relative;
}
.nm-sky .analog-inner {
position: absolute;
inset: 8px;
border-radius: 50%;
background: var(--nm-sky-ib);
box-shadow: var(--nm-sky-neu-sm-in);
}
.nm-sky .hand {
position: absolute;
bottom: 50%;
left: 50%;
transform-origin: bottom center;
border-radius: 3px;
}
.nm-sky .hand-h { width: 3px; height: 18px; margin-left: -1.5px; background: var(--nm-sky-txt2); }
.nm-sky .hand-m { width: 2px; height: 24px; margin-left: -1px; background: var(--nm-sky-sky); }
.nm-sky .hand-s { width: 1px; height: 26px; margin-left: -0.5px; background: var(--nm-sky-sun); }
.nm-sky .center-dot {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--nm-sky-sky);
z-index: 10;
box-shadow: 0 0 4px var(--nm-sky-sky);
}
/* Widget 3 — UV + Sunrise */
.nm-sky .w-uv {
display: flex;
flex-direction: column;
gap: 14px;
}
.nm-sky .uv-ring-wrap { display: flex; align-items: center; gap: 14px; }
.nm-sky .ring-sm {
position: relative;
width: 68px;
height: 68px;
flex-shrink: 0;
}
.nm-sky .ring-sm svg { width: 100%; height: 100%; }
.nm-sky .ring-sm-center {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
}
.nm-sky .ring-sm-val {
font-family: 'Space Mono', ui-monospace, monospace;
font-size: 16px;
font-weight: 700;
color: var(--nm-sky-txt2);
line-height: 1;
}
.nm-sky .ring-sm-val-warm { color: var(--nm-sky-warm); }
.nm-sky .ring-sm-sub {
font-size: 8px;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--nm-sky-txt);
}
.nm-sky .uv-info { flex: 1; }
.nm-sky .uv-level {
font-size: 14px;
font-weight: 800;
color: var(--nm-sky-txt2);
}
.nm-sky .uv-advice {
font-size: 11px;
color: var(--nm-sky-txt);
margin-top: 3px;
line-height: 1.4;
}
.nm-sky .sunrise-arc { position: relative; }
.nm-sky .sun-arc-svg { width: 100%; display: block; }
.nm-sky .sun-times {
display: flex;
justify-content: space-between;
font-size: 11px;
font-weight: 700;
color: var(--nm-sky-txt);
margin-top: 4px;
}
/* Widget 4 — Humidity */
.nm-sky .w-humidity {
display: flex;
flex-direction: column;
gap: 14px;
}
.nm-sky .hum-label {
font-size: 11px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 2px;
color: var(--nm-sky-txt);
}
.nm-sky .hum-arc-wrap { position: relative; }
.nm-sky .hum-arc-wrap svg { width: 100%; }
.nm-sky .hum-center {
position: absolute;
bottom: 6px;
left: 50%;
transform: translateX(-50%);
text-align: center;
}
.nm-sky .hum-pct {
font-family: 'Space Mono', ui-monospace, monospace;
font-size: 22px;
font-weight: 700;
color: var(--nm-sky-txt2);
}
.nm-sky .hum-unit { font-size: 10px; color: var(--nm-sky-sky); font-weight: 700; }
.nm-sky .hum-desc {
font-size: 12px;
color: var(--nm-sky-txt);
font-weight: 600;
text-align: center;
}
/* Widget 5 — Air Quality */
.nm-sky .w-air {
grid-column: 2 / 4;
display: flex;
align-items: center;
gap: 18px;
}
.nm-sky .aqi-chip {
width: 76px;
height: 76px;
border-radius: 50%;
background: var(--nm-sky-bg);
box-shadow: var(--nm-sky-neu);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
flex-shrink: 0;
position: relative;
}
.nm-sky .aqi-chip::after {
content: '';
position: absolute;
inset: 8px;
border-radius: 50%;
background: var(--nm-sky-ib);
box-shadow: var(--nm-sky-neu-sm-in);
}
.nm-sky .aqi-num {
font-family: 'Space Mono', ui-monospace, monospace;
font-size: 20px;
font-weight: 700;
color: var(--nm-sky-mnt);
z-index: 2;
line-height: 1;
position: relative;
}
.nm-sky .aqi-lbl {
font-size: 8px;
text-transform: uppercase;
letter-spacing: 1px;
color: var(--nm-sky-txt);
z-index: 2;
margin-top: 2px;
position: relative;
}
.nm-sky .aqi-bars { flex: 1; }
.nm-sky .aqi-title {
font-size: 13px;
font-weight: 800;
color: var(--nm-sky-txt2);
margin-bottom: 8px;
}
.nm-sky .aqi-scale {
display: flex;
gap: 4px;
height: 10px;
border-radius: 5px;
overflow: hidden;
}
.nm-sky .aqi-seg { border-radius: 3px; }
.nm-sky .aqi-seg-1 { background: var(--nm-sky-mnt); flex: 2; }
.nm-sky .aqi-seg-2 { background: var(--nm-sky-sun); flex: 2; }
.nm-sky .aqi-seg-3 { background: var(--nm-sky-warm); flex: 1.5; }
.nm-sky .aqi-seg-4 { background: #d04040; flex: 1.5; }
.nm-sky .aqi-seg-5 { background: #8040c0; flex: 1; }
.nm-sky .pollutants { display: flex; gap: 12px; margin-top: 10px; }
.nm-sky .poll-item {
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.nm-sky .poll-bar-bg {
width: 28px;
height: 36px;
border-radius: 6px;
background: var(--nm-sky-ib);
box-shadow: var(--nm-sky-neu-sm-in);
position: relative;
overflow: hidden;
}
.nm-sky .poll-bar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
border-radius: 4px;
background: linear-gradient(to top, var(--nm-sky-sky2), var(--nm-sky-sky));
}
.nm-sky .poll-bar-mnt { background: linear-gradient(to top, var(--nm-sky-mnt), #a0ddc8); }
.nm-sky .poll-bar-sun { background: linear-gradient(to top, var(--nm-sky-sun), #f8e090); }
.nm-sky .poll-bar-warm { background: linear-gradient(to top, var(--nm-sky-warm), #f0a880); }
.nm-sky .poll-name {
font-size: 9px;
font-weight: 700;
color: var(--nm-sky-txt);
letter-spacing: 0.5px;
}
.nm-sky .poll-val {
font-size: 10px;
font-weight: 800;
color: var(--nm-sky-txt2);
font-family: 'Space Mono', ui-monospace, monospace;
}
@media (max-width: 880px) {
.nm-sky .card {
grid-template-columns: 1fr;
}
.nm-sky .w-main { grid-row: auto; }
.nm-sky .w-air { grid-column: auto; }
}
@media (prefers-reduced-motion: reduce) {
.nm-sky .weather-emoji,
.nm-sky .dot-pulse { animation: none; }
} JS
(() => {
const root = document.querySelector('.nm-sky');
if (!root) return;
const clock = root.querySelector('[data-nm-sky-clock]');
const dateEl = root.querySelector('[data-nm-sky-date]');
const ampm = root.querySelector('[data-nm-sky-ampm]');
const handH = root.querySelector('[data-nm-sky-handh]');
const handM = root.querySelector('[data-nm-sky-handm]');
const handS = root.querySelector('[data-nm-sky-hands]');
function update() {
const now = new Date();
const h = now.getHours(), m = now.getMinutes(), s = now.getSeconds();
const ap = h >= 12 ? 'PM' : 'AM';
const h12 = h % 12 || 12;
if (clock) clock.innerHTML = String(h12).padStart(2, '0') + ':' + String(m).padStart(2, '0') + '<span class="clock-sec">:' + String(s).padStart(2, '0') + '</span>';
if (ampm) ampm.textContent = ap;
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
if (dateEl) dateEl.textContent = days[now.getDay()] + ', ' + months[now.getMonth()] + ' ' + now.getDate() + ', ' + now.getFullYear();
const sdeg = s * 6;
const mdeg = m * 6 + s * 0.1;
const hdeg = (h % 12) * 30 + m * 0.5;
if (handH) handH.style.transform = 'rotate(' + hdeg + 'deg)';
if (handM) handM.style.transform = 'rotate(' + mdeg + 'deg)';
if (handS) handS.style.transform = 'rotate(' + sdeg + 'deg)';
}
update();
setInterval(update, 1000);
})();