Back to CSS Neumorphism Sky Widgets CSS + JS
Share
HTML
<section class="nm-sky" aria-label="Sky weather widgets dashboard">
  <div class="card">

    <!-- Main weather widget -->
    <div class="widget w-main">
      <div class="city-row">
        <div>
          <div class="city-name">San Francisco</div>
          <div class="city-country">California, USA · 37.7°N</div>
        </div>
        <div class="live-dot">
          <div class="dot-pulse" aria-hidden="true"></div>
          Live
        </div>
      </div>

      <div class="temp-block">
        <div class="weather-icon-wrap" aria-hidden="true">
          <span class="weather-emoji">☀</span>
        </div>
        <div class="temp-right">
          <div class="temp-value">18<span class="temp-deg">°</span></div>
          <div class="temp-cond">Partly Cloudy</div>
          <div class="temp-feel">Feels like 16° · Wind 14 km/h NW</div>
        </div>
      </div>

      <div class="stats-strip">
        <div class="stat-cell">
          <div class="stat-icon" aria-hidden="true">💧</div>
          <div class="stat-val">72%</div>
          <div class="stat-nm">Humidity</div>
        </div>
        <div class="stat-cell">
          <div class="stat-icon" aria-hidden="true">👁</div>
          <div class="stat-val">14km</div>
          <div class="stat-nm">Visibility</div>
        </div>
        <div class="stat-cell">
          <div class="stat-icon" aria-hidden="true">💨</div>
          <div class="stat-val">14</div>
          <div class="stat-nm">km/h</div>
        </div>
        <div class="stat-cell">
          <div class="stat-icon" aria-hidden="true">☂</div>
          <div class="stat-val">20%</div>
          <div class="stat-nm">Rain</div>
        </div>
      </div>

      <div class="forecast-row">
        <div class="fc-day today">
          <div class="fc-day-name">Today</div>
          <div class="fc-icon" aria-hidden="true">☀</div>
          <div class="fc-bar-wrap" aria-hidden="true"><div class="fc-bar" style="height:65%"></div></div>
          <div class="fc-hi">18°</div>
          <div class="fc-lo">12°</div>
        </div>
        <div class="fc-day">
          <div class="fc-day-name">Sat</div>
          <div class="fc-icon" aria-hidden="true">☀️</div>
          <div class="fc-bar-wrap" aria-hidden="true"><div class="fc-bar" style="height:85%"></div></div>
          <div class="fc-hi">22°</div>
          <div class="fc-lo">14°</div>
        </div>
        <div class="fc-day">
          <div class="fc-day-name">Sun</div>
          <div class="fc-icon" aria-hidden="true">⛅</div>
          <div class="fc-bar-wrap" aria-hidden="true"><div class="fc-bar" style="height:75%"></div></div>
          <div class="fc-hi">20°</div>
          <div class="fc-lo">13°</div>
        </div>
        <div class="fc-day">
          <div class="fc-day-name">Mon</div>
          <div class="fc-icon" aria-hidden="true">🌧</div>
          <div class="fc-bar-wrap" aria-hidden="true"><div class="fc-bar" style="height:40%"></div></div>
          <div class="fc-hi">15°</div>
          <div class="fc-lo">10°</div>
        </div>
        <div class="fc-day">
          <div class="fc-day-name">Tue</div>
          <div class="fc-icon" aria-hidden="true">☁</div>
          <div class="fc-bar-wrap" aria-hidden="true"><div class="fc-bar" style="height:30%"></div></div>
          <div class="fc-hi">13°</div>
          <div class="fc-lo">9°</div>
        </div>
      </div>
    </div>

    <!-- Clock -->
    <div class="widget w-clock">
      <div class="clock-display">
        <div class="clock-time" data-nm-sky-clock>10:42<span class="clock-sec">:00</span></div>
        <div class="clock-date" data-nm-sky-date>Saturday, May 24, 2026</div>
      </div>
      <div class="clock-ampm" data-nm-sky-ampm>AM</div>
      <div class="analog-wrap">
        <div class="analog-face" aria-hidden="true">
          <div class="analog-inner"></div>
          <div class="hand hand-h" data-nm-sky-handh></div>
          <div class="hand hand-m" data-nm-sky-handm></div>
          <div class="hand hand-s" data-nm-sky-hands></div>
          <div class="center-dot"></div>
        </div>
      </div>
    </div>

    <!-- UV + Sunrise -->
    <div class="widget w-uv">
      <div class="uv-ring-wrap">
        <div class="ring-sm">
          <svg viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
            <circle cx="36" cy="36" r="28" fill="none" stroke="#dce5f0" stroke-width="7"/>
            <circle cx="36" cy="36" r="28" fill="none" stroke="#e07b50" stroke-width="7"
              stroke-linecap="round" stroke-dasharray="120 176" transform="rotate(-90 36 36)"/>
          </svg>
          <div class="ring-sm-center">
            <div class="ring-sm-val ring-sm-val-warm">4</div>
            <div class="ring-sm-sub">UV</div>
          </div>
        </div>
        <div class="uv-info">
          <div class="uv-level">Moderate</div>
          <div class="uv-advice">SPF 30 recommended. Safe until noon.</div>
        </div>
      </div>

      <div class="sunrise-arc">
        <svg class="sun-arc-svg" viewBox="0 0 240 90" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
          <defs>
            <linearGradient id="nm-sky-arcGrad" x1="0" y1="0" x2="1" y2="0">
              <stop offset="0%" stop-color="#f6c94e" stop-opacity="0.3"/>
              <stop offset="60%" stop-color="#f6c94e" stop-opacity="0.8"/>
              <stop offset="100%" stop-color="#e07b50" stop-opacity="0.3"/>
            </linearGradient>
            <filter id="nm-sky-sunGlow">
              <feGaussianBlur stdDeviation="3" result="b"/>
              <feMerge><feMergeNode in="b"/><feMergeNode in="SourceGraphic"/></feMerge>
            </filter>
          </defs>
          <path d="M 20 80 A 100 100 0 0 1 220 80" fill="none" stroke="#dce5f0" stroke-width="6" stroke-linecap="round"/>
          <path d="M 20 80 A 100 100 0 0 1 220 80" fill="none"
            stroke="url(#nm-sky-arcGrad)" stroke-width="6" stroke-linecap="round"
            stroke-dasharray="165 315" stroke-dashoffset="0"/>
          <circle cx="148" cy="22" r="12" fill="#f6c94e" opacity="0.2"/>
          <circle cx="148" cy="22" r="6" fill="#f6c94e" filter="url(#nm-sky-sunGlow)"/>
        </svg>
        <div class="sun-times">
          <span>🌅 6:14 AM</span>
          <span>🌇 8:02 PM</span>
        </div>
      </div>
    </div>

    <!-- Humidity gauge -->
    <div class="widget w-humidity">
      <div class="hum-label">💧 Humidity</div>
      <div class="hum-arc-wrap">
        <svg viewBox="0 0 160 100" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
          <defs>
            <linearGradient id="nm-sky-humGrad" x1="0" y1="0" x2="1" y2="0">
              <stop offset="0%" stop-color="#5b9ec9"/>
              <stop offset="100%" stop-color="#78bda8"/>
            </linearGradient>
          </defs>
          <path d="M 16 88 A 64 64 0 0 1 144 88" fill="none" stroke="#dce5f0" stroke-width="10" stroke-linecap="round"/>
          <path d="M 16 88 A 64 64 0 0 1 144 88" fill="none"
            stroke="url(#nm-sky-humGrad)" stroke-width="10" stroke-linecap="round"
            stroke-dasharray="131 202"/>
        </svg>
        <div class="hum-center">
          <div class="hum-pct">72<span class="hum-unit">%</span></div>
        </div>
      </div>
      <div class="hum-desc">Comfortable range</div>
    </div>

    <!-- Air quality wide -->
    <div class="widget w-air">
      <div class="aqi-chip">
        <div class="aqi-num">38</div>
        <div class="aqi-lbl">AQI</div>
      </div>
      <div class="aqi-bars">
        <div class="aqi-title">🌿 Air Quality · Good</div>
        <div class="aqi-scale" aria-hidden="true">
          <div class="aqi-seg aqi-seg-1"></div>
          <div class="aqi-seg aqi-seg-2"></div>
          <div class="aqi-seg aqi-seg-3"></div>
          <div class="aqi-seg aqi-seg-4"></div>
          <div class="aqi-seg aqi-seg-5"></div>
        </div>
        <div class="pollutants">
          <div class="poll-item">
            <div class="poll-bar-bg" aria-hidden="true"><div class="poll-bar" style="height:35%"></div></div>
            <div class="poll-name">PM2.5</div>
            <div class="poll-val">12</div>
          </div>
          <div class="poll-item">
            <div class="poll-bar-bg" aria-hidden="true"><div class="poll-bar poll-bar-mnt" style="height:28%"></div></div>
            <div class="poll-name">PM10</div>
            <div class="poll-val">22</div>
          </div>
          <div class="poll-item">
            <div class="poll-bar-bg" aria-hidden="true"><div class="poll-bar poll-bar-sun" style="height:18%"></div></div>
            <div class="poll-name">O₃</div>
            <div class="poll-val">38</div>
          </div>
          <div class="poll-item">
            <div class="poll-bar-bg" aria-hidden="true"><div class="poll-bar poll-bar-warm" style="height:10%"></div></div>
            <div class="poll-name">NO₂</div>
            <div class="poll-val">8</div>
          </div>
          <div class="poll-item">
            <div class="poll-bar-bg" aria-hidden="true"><div class="poll-bar" style="height:8%"></div></div>
            <div class="poll-name">CO</div>
            <div class="poll-val">0.4</div>
          </div>
        </div>
      </div>
    </div>

  </div>
</section>
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);
})();