:root {
  --wii: #34beed;
  --wii-deep: #1a8fd0;
  --ink: #22324a;
  --ink-soft: #5d6f88;
  --glass: rgba(250, 252, 255, 0.84);
  --glass-edge: rgba(255, 255, 255, 0.9);
  --glass-dark: rgba(12, 24, 46, 0.55);
  --hi: #f2622e;
  --lo: #2c86e0;
  --rain: #2a8ee8;
  --shadow: 0 18px 50px -18px rgba(3, 12, 30, 0.65), 0 2px 6px rgba(3, 12, 30, 0.18);
  --r: 26px;
  --font: 'M PLUS Rounded 1c', ui-rounded, 'Segoe UI', system-ui, sans-serif;
  --top: 84px;
  --bottom: 150px;
}

* { box-sizing: border-box; }
/* A solid colour on the root as well as the gradient: Safari fills any area
   the page doesn't cover (in the home-screen app, sometimes the strip where
   its toolbar would be) with the root's background colour, and with only a
   gradient there that fill was white. */
html { background: #050b18; }
html, body { height: 100%; }
body {
  margin: 0;
  overflow: hidden;
  font-family: var(--font);
  color: var(--ink);
  background: #050b18 radial-gradient(ellipse at 70% 40%, #0e2246 0%, #050b18 60%, #02050c 100%);
  -webkit-font-smoothing: antialiased;
}
button { font: inherit; color: inherit; cursor: pointer; }
h1, h2, h3 { margin: 0; }

/* ---------- globe & labels ---------- */
/* min-height: the full screen even if the layout viewport stops short of it
   (seen in the iOS home-screen app). */
.globe { position: fixed; inset: 0; min-height: 100lvh; }
.globe canvas { width: 100%; height: 100%; display: block; opacity: 0; transition: opacity 0.8s ease; touch-action: none; }
body.globe-ready .globe canvas { opacity: 1; }
.globe[data-mode="globe"] canvas, .globe[data-mode="region"] canvas { cursor: grab; }
.globe[data-mode="globe"] canvas:active, .globe[data-mode="region"] canvas:active { cursor: grabbing; }
body.no-webgl { background: linear-gradient(180deg, #5cc4ff 0%, #a9e3ff 55%, #e9f7ff 100%); }

.labels { position: fixed; inset: 0; pointer-events: none; overflow: hidden; }
.g-label {
  position: absolute; left: 0; top: 0; visibility: hidden;
  display: flex; align-items: center; gap: 4px;
  padding: 2px 10px 2px 4px; border: 0; border-radius: 999px;
  background: rgba(255, 255, 255, 0.88); box-shadow: 0 4px 14px rgba(0, 10, 30, 0.35);
  font-size: 12px; font-weight: 700; color: var(--ink); white-space: nowrap;
  pointer-events: auto; transition: opacity 0.2s, background 0.15s;
}
.g-label::after {
  content: ''; position: absolute; left: 50%; bottom: -5px; width: 8px; height: 8px;
  background: inherit; transform: translateX(-50%) rotate(45deg); border-radius: 2px;
}
.g-label:hover { background: #fff; z-index: 10 !important; }
.g-label .wx-icon { flex: none; }
.g-temp { color: var(--ink); font-size: 13px; }
.g-hilo { display: flex; gap: 5px; font-size: 13px; }
.hi { color: var(--hi); }
.lo { color: var(--lo); }
body[data-view="region"] .g-label { flex-direction: column; gap: 0; padding: 4px 9px 6px; border-radius: 16px; }
body[data-view="region"] .g-label .g-name { font-size: 11px; color: var(--ink-soft); }
.g-label.is-home { padding: 5px 12px 5px 8px; background: #fff; font-size: 13px; }
.g-label.is-home b { color: var(--wii-deep); margin-left: 4px; }
/* The pulse scales a pseudo-element (transform + opacity only) so it stays
   on the compositor instead of repainting a box-shadow every frame. */
.pin { position: relative; width: 12px; height: 12px; border-radius: 50%; background: #ff4f63; box-shadow: 0 0 0 3px rgba(255, 79, 99, 0.3); }
.pin::after { content: ''; position: absolute; inset: 0; border-radius: 50%; background: rgba(255, 79, 99, 0.55); animation: ping 2s ease-out infinite; }
@keyframes ping { 0% { transform: scale(1); opacity: 1; } 80%, 100% { transform: scale(2.6); opacity: 0; } }
body:not(.started) .labels { opacity: 0; }

.pick-card {
  position: fixed; z-index: 30; transform: translate(-50%, calc(-100% - 14px));
  padding: 12px 14px; border-radius: 18px; text-align: center; min-width: 170px;
  animation: pop 0.22s cubic-bezier(.3, 1.6, .5, 1);
}
.pick-where { font-weight: 800; }
.pick-coord { font-size: 12px; color: var(--ink-soft); margin: 2px 0 8px; }
@keyframes pop { from { transform: translate(-50%, calc(-100% - 4px)) scale(0.85); opacity: 0; } }

/* ---------- shared bits ---------- */
.glass {
  background: var(--glass);
  -webkit-backdrop-filter: blur(22px) saturate(1.4);
  backdrop-filter: blur(22px) saturate(1.4);
  border: 1px solid var(--glass-edge);
  box-shadow: var(--shadow), inset 0 1px 0 rgba(255, 255, 255, 0.9);
}
.pill {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  border: 0; border-radius: 999px; padding: 12px 26px; font-weight: 800;
  color: #fff; background: linear-gradient(180deg, #5fd3ff 0%, var(--wii) 45%, var(--wii-deep) 100%);
  box-shadow: 0 6px 16px -6px rgba(26, 143, 208, 0.9), inset 0 1px 0 rgba(255, 255, 255, 0.6), inset 0 -2px 0 rgba(0, 60, 120, 0.25);
  transition: transform 0.15s, filter 0.15s;
}
.pill:hover { filter: brightness(1.07); transform: translateY(-1px); }
.pill:active { transform: translateY(1px) scale(0.98); }
.pill.small { padding: 7px 14px; font-size: 13px; }
.pill.ghost { background: #fff; color: var(--wii-deep); box-shadow: inset 0 0 0 2px #cfe9f8, 0 4px 10px -6px rgba(0, 40, 80, 0.4); }
.round {
  width: 42px; height: 42px; border-radius: 50%; border: 0; display: grid; place-items: center;
  font-weight: 800; font-size: 15px; color: var(--ink); transition: transform 0.15s;
}
.round:hover { transform: scale(1.07); }
:focus-visible { outline: 3px solid var(--wii); outline-offset: 2px; }

/* ---------- top bar ---------- */
.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 10;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px;
  padding: 16px 22px; pointer-events: none;
}
.topbar > * { pointer-events: auto; }
.brand { display: flex; align-items: center; gap: 10px; color: #fff; font-weight: 800; font-size: 20px; letter-spacing: 0.02em; text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5); }
.loc-chip {
  display: flex; align-items: center; gap: 10px; border-radius: 999px; padding: 8px 16px 8px 12px;
  border: 0; min-width: 240px; text-align: left; transition: transform 0.15s;
}
.loc-chip:hover { transform: translateY(-1px); }
/* The home pin shows only at home; without it the name gets a little more room. */
.loc-chip .home-pin { display: none; flex: none; }
.loc-chip.home .home-pin { display: block; }
.loc-chip:not(.home) { padding-left: 20px; }
/* The location chip and, to its right, the go-home button. */
.loc-wrap { display: flex; align-items: center; gap: 8px; min-width: 0; }
.loc-wrap .loc-chip { flex: 1; }
#home-btn { flex: none; width: 46px; height: 46px; }
.loc-text { display: flex; flex-direction: column; line-height: 1.15; flex: 1; min-width: 0; }
.loc-text b { font-size: 17px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.loc-text small { color: var(--ink-soft); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chev { color: var(--ink-soft); }
.top-actions { display: flex; align-items: center; gap: 10px; justify-content: flex-end; }
.clock { color: #fff; font-weight: 800; font-size: 22px; white-space: nowrap; text-shadow: 0 2px 10px rgba(0, 0, 0, 0.5); margin-right: 6px; font-variant-numeric: tabular-nums; }
#music .mute, #calm-music .mute { display: none; }
#music.off, #calm-music.off { color: var(--ink-soft); }
#music.off .mute, #calm-music.off .mute { display: block; }
/* Calm View's copy sits in the top-right corner, level with Back to Globe. */
#calm-music { position: absolute; z-index: 2; top: calc(12px + env(safe-area-inset-top)); right: max(14px, env(safe-area-inset-right)); text-shadow: none; }


/* ---------- stage & panel ---------- */
.stage {
  position: fixed; z-index: 5; top: var(--top); bottom: var(--bottom); left: 0; right: 0;
  display: flex; align-items: center; gap: 14px; padding: 18px 28px 12px; pointer-events: none;
}
.stage > * { pointer-events: auto; }
.panel {
  width: min(600px, 50vw); max-height: 100%; border-radius: var(--r);
  display: flex; flex-direction: column; overflow: hidden;
  transition: opacity 0.16s ease, transform 0.16s ease, width 0.35s ease;
}
.panel.swap { opacity: 0; transform: translateX(-10px) scale(0.99); }
.panel-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  padding: 16px 24px 12px; border-bottom: 1px solid rgba(34, 50, 74, 0.08);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0));
}
.panel-head h1 { font-size: 22px; font-weight: 800; }
#panel-date { color: var(--ink-soft); font-size: 14px; font-weight: 500; }
.panel-body { padding: 18px 24px 22px; overflow: auto; scrollbar-width: thin; }
.page-arrow {
  flex: none; width: 52px; height: 52px; border-radius: 50%; border: 0; color: #fff; display: grid; place-items: center;
  background: linear-gradient(180deg, #6cd8ff, var(--wii) 50%, var(--wii-deep));
  box-shadow: 0 8px 20px -6px rgba(26, 143, 208, 0.9), inset 0 1px 0 rgba(255, 255, 255, 0.6);
  transition: transform 0.15s;
}
.page-arrow:hover { transform: scale(1.1); }
.page-arrow.right { order: 2; }

/* Globe & region: panel shrinks to a small control card so the Earth can be touched. */
body[data-view="globe"] .panel, body[data-view="region"] .panel { width: min(360px, 90vw); align-self: flex-end; }
body[data-view="globe"] .panel-head, body[data-view="region"] .panel-head { padding: 12px 18px 8px; }
body[data-view="globe"] .panel-body, body[data-view="region"] .panel-body { padding: 10px 18px 16px; }
body[data-view="globe"] #panel-date, body[data-view="region"] #panel-date { display: none; }
body[data-view="globe"] .stage, body[data-view="region"] .stage { align-items: flex-end; }

/* ---------- dock & ticker ---------- */
.dock {
  position: fixed; z-index: 8; bottom: 52px; left: 50%; transform: translateX(-50%);
  display: flex; border-radius: 26px; max-width: calc(100vw - 24px);
}
/* The buttons scroll inside the track, which fades out on any side with more
   buttons (--fade-l/r from dockFades() in app.js); the glass stays solid. */
.dock-track {
  /* The padding is inside the scroller so the current button's glow and the
     hover lift aren't clipped. */
  position: relative; flex: 1; min-width: 0; display: flex; gap: 4px; padding: 6px; overflow-x: auto; scrollbar-width: none;
  border-radius: inherit;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 var(--fade-l, 0px), #000 calc(100% - var(--fade-r, 0px)), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 var(--fade-l, 0px), #000 calc(100% - var(--fade-r, 0px)), transparent 100%);
}
.dock-track::-webkit-scrollbar { display: none; }
.dock button {
  flex: none; display: flex; flex-direction: column; align-items: center; gap: 2px;
  width: 74px; padding: 8px 4px 6px; border: 0; border-radius: 20px; background: transparent;
  color: var(--ink-soft); font-size: 12px; font-weight: 700; transition: background 0.15s, color 0.15s, transform 0.15s;
}
.dock button:hover { background: rgba(52, 190, 237, 0.12); color: var(--wii-deep); transform: translateY(-2px); }
.dock button[aria-current="page"] {
  color: #fff; background: linear-gradient(180deg, #5fd3ff, var(--wii) 50%, var(--wii-deep));
  box-shadow: 0 6px 14px -6px rgba(26, 143, 208, 0.9), inset 0 1px 0 rgba(255, 255, 255, 0.55);
}

.ticker {
  position: fixed; z-index: 7; bottom: 0; left: 0; right: 0; height: 40px; overflow: hidden;
  background: linear-gradient(180deg, rgba(8, 20, 42, 0.78), rgba(8, 20, 42, 0.94));
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
/* Scrolled by tickerFrame() in app.js; see the note there. */
.ticker-track { display: flex; width: max-content; height: 100%; will-change: transform; }
.tick-run { display: flex; align-items: center; }
.tick-item {
  display: flex; align-items: center; gap: 6px; padding: 0 18px; height: 40px; border: 0; background: none;
  color: #e6f2ff; font-size: 13px; font-weight: 500; white-space: nowrap; border-right: 1px solid rgba(255, 255, 255, 0.08);
}
.tick-item b { color: #fff; }
.tick-item:hover { background: rgba(255, 255, 255, 0.08); }

/* ---------- intro ---------- */
.intro {
  position: fixed; inset: 0; z-index: 40; display: grid; place-items: center; padding: 16px;
  background: radial-gradient(ellipse at center, rgba(5, 11, 24, 0) 30%, rgba(5, 11, 24, 0.7) 100%);
  transition: opacity 0.7s ease, visibility 0.7s;
}
body.started .intro { opacity: 0; visibility: hidden; pointer-events: none; }
body:not(.started) .topbar, body:not(.started) .stage, body:not(.started) .dock, body:not(.started) .ticker { opacity: 0; pointer-events: none; }
.topbar, .stage, .dock, .ticker { transition: opacity 0.35s ease, transform 0.35s ease; }
.intro-card { display: flex; flex-direction: column; align-items: center; gap: 26px; text-align: center; margin-top: 34vh; }
.intro-logo {
  padding: 22px 46px 26px; border-radius: 36px; color: #fff;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.06));
  border: 1px solid rgba(255, 255, 255, 0.35); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  box-shadow: 0 20px 60px -20px rgba(0, 0, 0, 0.7);
}
.intro-logo h2 { font-size: clamp(38px, 7vw, 68px); font-weight: 800; letter-spacing: 0.01em; line-height: 1; text-shadow: 0 4px 24px rgba(52, 190, 237, 0.6); }
.intro-logo em { font-style: normal; color: #8fe0ff; }
.intro-sub { display: block; font-size: 14px; letter-spacing: 0.25em; text-transform: uppercase; opacity: 0.8; margin-bottom: 8px; }
.pill.start { position: relative; font-size: 22px; padding: 16px 64px; }
.pill.start::after { content: ''; position: absolute; inset: 0; border-radius: inherit; box-shadow: 0 0 0 10px rgba(52, 190, 237, 0.2); opacity: 0; animation: breathe 2.4s ease-in-out infinite; pointer-events: none; }
@keyframes breathe { 50% { opacity: 1; } }
.intro-fine { color: rgba(230, 242, 255, 0.7); font-size: 12px; margin: 0; }
.intro-version { color: rgba(230, 242, 255, 0.45); font-size: 11px; font-weight: 700; letter-spacing: 0.06em; margin: -18px 0 0; font-variant-numeric: tabular-nums; }

/* ---------- screen content ---------- */
.cond { font-size: 22px; font-weight: 800; }
.pop { display: inline-flex; align-items: center; gap: 4px; color: var(--rain); font-weight: 700; font-size: 13px; }
.pop.big { font-size: 15px; margin-top: 6px; }
.fine { font-size: 12px; color: var(--ink-soft); margin: 12px 0 0; }
.hint { margin: 0 0 10px; font-size: 13px; color: var(--ink-soft); }
.empty { text-align: center; padding: 18px 8px; }
.empty h3 { font-size: 18px; margin: 8px 0; }
.empty p { color: var(--ink-soft); margin: 8px auto 14px; max-width: 40ch; }

.now { display: flex; align-items: center; gap: 12px; }
.now-icon { flex: none; filter: drop-shadow(0 10px 18px rgba(20, 60, 120, 0.25)); }
.now-temp { font-size: 84px; font-weight: 800; line-height: 0.95; letter-spacing: -0.02em; }
.feels { color: var(--ink-soft); font-size: 14px; margin-top: 2px; }
.hilo-row { display: flex; gap: 16px; align-items: center; margin-top: 10px; font-size: 14px; color: var(--ink-soft); }
.hilo-row b { font-size: 20px; }
.stats { display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; margin: 12px 0 0; }
.stat { background: rgba(255, 255, 255, 0.7); border-radius: 16px; padding: 10px 10px; box-shadow: inset 0 0 0 1px rgba(34, 50, 74, 0.06); }
.stat span { display: block; font-size: 11px; color: var(--ink-soft); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
.stat b { font-size: 14px; }
.wind-arrow { display: inline-block; font-style: normal; color: var(--wii-deep); }
.hours { display: flex; gap: 6px; overflow-x: auto; margin-top: 16px; padding-bottom: 4px; scrollbar-width: thin; }
.hour { flex: none; width: 62px; display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 8px 2px; border-radius: 16px; background: rgba(255, 255, 255, 0.55); }
.h-time { font-size: 11px; color: var(--ink-soft); font-weight: 700; }

.day-hero { display: flex; align-items: center; gap: 18px; }
.hilo-big { display: flex; gap: 14px; font-size: 48px; font-weight: 800; line-height: 1.05; }
.blocks { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 14px; }
.block {
  display: flex; flex-direction: column; align-items: center; padding: 12px 6px; border-radius: 20px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.95), rgba(236, 245, 252, 0.8));
  box-shadow: inset 0 0 0 1px rgba(34, 50, 74, 0.06);
}
.block.past { opacity: 0.45; }
.block-label { font-weight: 800; font-size: 14px; }
.block-range { font-size: 11px; color: var(--ink-soft); }
.block-temp { font-size: 22px; font-weight: 800; }
.nws { margin-top: 14px; padding: 12px 14px; border-radius: 16px; background: rgba(255, 255, 255, 0.65); font-size: 13px; line-height: 1.5; }
.nws-head { font-size: 11px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--wii-deep); font-weight: 800; }
.nws p { margin: 6px 0 0; }

.alerts { display: grid; gap: 6px; margin-bottom: 14px; }
.alert { border-radius: 14px; background: #fff3d6; border: 1px solid #f5c860; font-size: 13px; }
.alert.sev-severe, .alert.sev-extreme { background: #ffe1e1; border-color: #f08a8a; }
.alert summary { cursor: pointer; padding: 9px 12px; font-weight: 800; display: flex; align-items: center; gap: 8px; }
.alert summary small { margin-left: auto; font-weight: 500; color: var(--ink-soft); }
.alert-dot { width: 9px; height: 9px; border-radius: 50%; background: #e8a400; flex: none; }
.sev-severe .alert-dot, .sev-extreme .alert-dot { background: #e0393e; }
.alert p { margin: 0 12px 10px; line-height: 1.45; }
.alert-desc { max-height: 180px; overflow: auto; color: var(--ink-soft); }

.week { position: relative; display: grid; grid-template-columns: repeat(5, 1fr); gap: 8px; }
.day-card {
  display: flex; flex-direction: column; align-items: center; padding: 14px 4px 12px; border-radius: 22px; text-align: center;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.95), rgba(236, 245, 252, 0.8));
  box-shadow: inset 0 0 0 1px rgba(34, 50, 74, 0.06);
}
.day-name { font-weight: 800; font-size: 16px; }
.day-date { font-size: 12px; color: var(--ink-soft); margin-bottom: 2px; }
.day-cond { font-size: 12px; color: var(--ink-soft); min-height: 2.4em; display: grid; place-items: center; line-height: 1.2; }
.day-hilo { display: flex; gap: 8px; font-size: 20px; margin: 4px 0; }

.seg { display: flex; padding: 4px; gap: 4px; border-radius: 999px; background: rgba(34, 50, 74, 0.07); }
.seg button { flex: 1; border: 0; border-radius: 999px; padding: 8px 10px; background: none; font-weight: 700; font-size: 13px; color: var(--ink-soft); }
.seg button[aria-pressed="true"] { background: #fff; color: var(--wii-deep); box-shadow: 0 2px 8px rgba(0, 30, 70, 0.15); }

.uv { display: grid; grid-template-columns: 1fr 1.1fr; gap: 18px; align-items: center; }
.gauge { position: relative; text-align: center; }
.gauge svg { width: 100%; max-width: 280px; display: block; margin: 0 auto; overflow: visible; }
.gauge-arcs path { fill: none; stroke-width: 22; stroke-linecap: round; }
.gauge-arcs .uv-low { stroke: #4cc35a; } .gauge-arcs .uv-mod { stroke: #f4d03f; } .gauge-arcs .uv-high { stroke: #f39c32; }
.gauge-arcs .uv-vhigh { stroke: #e5484d; } .gauge-arcs .uv-ext { stroke: #9b59d0; }
.needle { transform-origin: 100px 100px; transition: transform 1s cubic-bezier(.3, 1.4, .5, 1); }
.needle path, .needle circle { fill: var(--ink); }
.uv-num { font-size: 60px; font-weight: 800; line-height: 1; margin-top: -4px; }
.uv-num.uv-low { color: #2e9e3c; } .uv-num.uv-mod { color: #c9a100; } .uv-num.uv-high { color: #e07f12; }
.uv-num.uv-vhigh { color: #d23339; } .uv-num.uv-ext { color: #8a44c4; }
.uv-cat { font-size: 20px; font-weight: 800; }
.uv-sub { font-size: 12px; color: var(--ink-soft); margin-top: 4px; }
.uv-tip { margin: 0 0 12px; font-weight: 500; line-height: 1.45; }
.uv-bars { display: flex; align-items: flex-end; gap: 3px; height: 110px; }
.uv-bar { flex: 1; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; }
.uv-bar i { width: 100%; border-radius: 6px 6px 2px 2px; transition: height 0.6s; }
.uv-bar i.uv-low { background: #4cc35a; } .uv-bar i.uv-mod { background: #f4d03f; } .uv-bar i.uv-high { background: #f39c32; }
.uv-bar i.uv-vhigh { background: #e5484d; } .uv-bar i.uv-ext { background: #9b59d0; }
.uv-bar span { font-size: 10px; color: var(--ink-soft); height: 14px; white-space: nowrap; }

.laundry-hero { text-align: center; color: var(--ink-soft); }
.clothesline { display: block; margin: 0 auto; max-width: 100%; height: auto; }
.shirt.on { animation: sway 3s ease-in-out infinite; transform-box: fill-box; transform-origin: 50% 0; }
@keyframes sway { 50% { transform: rotate(4deg); } }
.laundry-text { font-size: 28px; font-weight: 800; color: var(--ink); margin-top: 4px; }
.laundry-score { display: flex; align-items: baseline; justify-content: center; gap: 6px; }
.laundry-score b { font-size: 26px; color: var(--wii-deep); }
.laundry-why { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin-top: 10px; }
.laundry-why span { display: inline-flex; align-items: center; gap: 4px; padding: 5px 10px; border-radius: 999px; background: rgba(255, 255, 255, 0.8); font-size: 12px; font-weight: 700; color: var(--ink); }
.laundry-days { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 16px; }
.mini-day { text-align: center; padding: 10px 4px; border-radius: 18px; background: rgba(255, 255, 255, 0.7); color: var(--ink-soft); }
.mini-day .day-name { color: var(--ink); font-size: 14px; }
.mini-day small { display: block; font-size: 11px; font-weight: 700; line-height: 1.2; }

.lvl-0 { background: #e8f6ea; color: #2e7d3a; }

.toggles { display: grid; gap: 10px; margin: 6px 0 4px; }
.switch { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 14px; cursor: pointer; }
.switch input { position: absolute; opacity: 0; }
.switch span { flex: none; width: 46px; height: 28px; border-radius: 999px; background: #cfd8e3; position: relative; transition: background 0.2s; }
.switch span::after { content: ''; position: absolute; top: 3px; left: 3px; width: 22px; height: 22px; border-radius: 50%; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.25); transition: transform 0.2s cubic-bezier(.3, 1.5, .5, 1); }
.switch input:checked + span { background: var(--wii); }
.switch input:checked + span::after { transform: translateX(18px); }
.switch input:focus-visible + span { outline: 3px solid var(--wii); outline-offset: 2px; }

/* ---------- dialogs & toast ---------- */
.sheet {
  width: min(480px, calc(100vw - 32px)); max-height: min(640px, calc(100dvh - 40px)); padding: 20px 22px 22px;
  border: 0; border-radius: 28px; color: var(--ink); background: rgba(250, 252, 255, 0.96); box-shadow: var(--shadow);
}
.sheet.wide { width: min(640px, calc(100vw - 32px)); line-height: 1.5; font-size: 14px; }
.sheet::backdrop { background: rgba(3, 10, 24, 0.45); -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px); }
.sheet[open] { animation: rise 0.28s cubic-bezier(.3, 1.4, .5, 1); }
@keyframes rise { from { transform: translateY(16px) scale(0.97); opacity: 0; } }
.sheet-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.sheet-head h2 { font-size: 20px; }
.sheet-head .round { background: #edf1f6; }
.sheet h3 { font-size: 15px; margin: 16px 0 4px; }
.sheet a { color: var(--wii-deep); font-weight: 700; }
.sources { padding-left: 18px; margin: 6px 0; }
.sources li { margin-bottom: 6px; }
#loc-q {
  width: 100%; padding: 14px 18px; border-radius: 999px; border: 2px solid #d5e4f0; font: inherit; font-size: 16px;
  background: #fff; color: var(--ink); outline: none;
}
#loc-q:focus { border-color: var(--wii); }
.geo { width: 100%; margin: 10px 0 8px; }
.check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-soft); margin: 2px 4px 8px; }
.results { list-style: none; padding: 0; margin: 0; }
.results li.muted { padding: 10px 6px; color: var(--ink-soft); font-size: 14px; }
.results button {
  width: 100%; display: flex; flex-direction: column; align-items: flex-start; padding: 10px 14px; border: 0; border-radius: 14px; background: none; text-align: left;
}
.results button:hover, .results button:focus-visible { background: rgba(52, 190, 237, 0.12); }
.results button span { font-size: 12px; color: var(--ink-soft); }

/* The place on screen, with "Set as home". */
.loc-current {
  display: flex; align-items: center; gap: 10px; margin: 0 0 12px; padding: 10px 10px 10px 12px;
  border-radius: 18px; background: rgba(52, 190, 237, 0.09);
}
.loc-current svg { flex: none; }
.loc-current .home-pin, .loc-current.home .pin { display: none; }
.loc-current.home .home-pin { display: block; }
.loc-current-text { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.2; }
.loc-current-text small { font-size: 11px; font-weight: 800; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-soft); }
.loc-current-text b { font-size: 15px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.loc-current-text span { font-size: 12px; color: var(--ink-soft); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#loc-make-home { flex: none; }
.loc-is-home {
  display: none; flex: none; padding: 5px 10px; border-radius: 999px; font-size: 12px; font-weight: 800;
  color: var(--wii-deep); background: rgba(52, 190, 237, 0.16);
}
.loc-current.home #loc-make-home { display: none; }
.loc-current.home .loc-is-home { display: inline-block; }

/* The location dialog's results scroll inside it. On phones it sits near the
   top, away from the keyboard. */
#loc-dialog[open] { display: flex; flex-direction: column; }
/* flex-basis auto, not the 0% that "flex: 1" sets: Safari keeps a 0%-basis
   item at zero height in a column whose height isn't fixed, which hid every
   result (and the hint) on iPhones. */
#loc-dialog .results { flex: 1 1 auto; min-height: 0; overflow-y: auto; }
@media (max-width: 860px) {
  #loc-dialog { margin: calc(12px + env(safe-area-inset-top)) auto auto; max-height: calc(100dvh - 24px - env(safe-area-inset-top)); }
}
/* With an on-screen keyboard up (phones and tablets), it fits the space that's
   left: --kb-shift is the measured correction that puts its top 10px below the
   status bar in the visible area, --vv-height that area's height (both from
   fitToKeyboard() in app.js). While typing, the GPS button steps aside to give
   the results room (it comes back when the keyboard closes); the current place
   and Set as home stay. */
#loc-dialog.keyboard {
  margin: calc(12px + env(safe-area-inset-top) + var(--kb-shift, 0px)) auto auto;
  max-height: calc(var(--vv-height, 100dvh) - 20px - env(safe-area-inset-top));
}
#loc-dialog.keyboard .geo { display: none; }

.toast {
  position: fixed; z-index: 50; left: 50%; bottom: 130px; transform: translate(-50%, 20px); opacity: 0;
  padding: 10px 18px; border-radius: 999px; background: rgba(12, 24, 46, 0.9); color: #fff; font-size: 14px; font-weight: 700;
  pointer-events: none; transition: opacity 0.25s, transform 0.25s;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }

/* ---------- weather icon motion ---------- */
.wx-icon { overflow: visible; }
.wx-anim .wx-spin { animation: spin 24s linear infinite; transform-box: fill-box; transform-origin: center; }
@keyframes spin { to { transform: rotate(360deg); } }
.wx-anim .wx-drop { animation: fall 1.1s ease-in infinite; }
@keyframes fall { 0% { transform: translateY(-6px); opacity: 0; } 25% { opacity: 1; } 100% { transform: translateY(8px); opacity: 0; } }
.wx-anim .wx-flake { animation: drift 2.4s ease-in-out infinite; }
@keyframes drift { 0% { transform: translate(0, -5px); opacity: 0; } 30% { opacity: 1; } 100% { transform: translate(3px, 7px); opacity: 0; } }
.wx-anim .wx-flash { animation: flash 3s steps(1) infinite; }
@keyframes flash { 0%, 100% { opacity: 1; } 82% { opacity: 0.2; } 86% { opacity: 1; } 90% { opacity: 0.3; } }
.wx-anim .wx-twinkle { animation: twinkle 2.5s ease-in-out infinite; }
@keyframes twinkle { 50% { opacity: 0.35; } }
/* Only large "hero" icons animate (iconSVG adds .wx-anim at size >= 70). SVG
   transform animations repaint on the main thread in Firefox, so dozens of
   small animated icons in hourly strips were a steady drain. */

/* ---------- responsive ---------- */
@media (max-width: 860px) {
  :root { --top: 132px; --bottom: 132px; }
  .topbar { grid-template-columns: auto 1fr; grid-template-rows: auto auto; padding: 12px 16px; row-gap: 10px; }
  .brand span { display: none; }
  .top-actions { grid-column: 2; grid-row: 1; }
  .loc-wrap { grid-column: 1 / -1; grid-row: 2; }
  .loc-chip { min-width: 0; }
  .stage { padding: 8px 16px; align-items: flex-end; top: 36vh; }
  .page-arrow { display: none; }
  .panel { width: 100%; }
  .dock { bottom: 46px; border-radius: 22px; left: 16px; right: 16px; transform: none; max-width: none; }
  .dock button { width: 64px; font-size: 11px; }
  /* When the buttons don't all fit, size them so the last one on screen is
     cut in half: the usual cue that a row scrolls. How many show depends on
     the width, keeping buttons near their natural size. Container units are
     the track's width; each line is (width - gaps) / buttons showing. */
  .dock-track { container: dock / inline-size; }
  @container dock (max-width: 607px) { .dock button { width: calc((100cqw - 28px) / 7.5); } }
  @container dock (max-width: 540px) { .dock button { width: calc((100cqw - 24px) / 6.5); } }
  @container dock (max-width: 460px) { .dock button { width: calc((100cqw - 20px) / 5.5); } }
  @container dock (max-width: 380px) { .dock button { width: calc((100cqw - 16px) / 4.5); } }
  .ticker { height: 36px; }
  .tick-item { height: 36px; }
  body[data-view="globe"] .panel, body[data-view="region"] .panel { width: 100%; }
  body[data-view="globe"] .stage, body[data-view="region"] .stage { top: auto; height: auto; }
  .stats { grid-template-columns: repeat(3, 1fr); }
  .week { grid-template-columns: repeat(5, minmax(84px, 1fr)); overflow-x: auto; }
  .uv { grid-template-columns: 1fr; }
  .laundry-days { grid-template-columns: repeat(2, 1fr); }
  .intro-card { margin-top: 28vh; }
}
@media (max-width: 860px) and (max-height: 760px) { .stage { top: 30vh; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; transition-duration: 0.001ms !important; }
  .ticker { overflow-x: auto; }
}

/* ---------- localization ---------- */
/* Chinese uses Noto Sans SC (loaded on demand) so Han characters get
   Simplified Chinese glyph forms rather than the Japanese ones in M PLUS. */
:root:lang(zh-CN) { --font: 'Noto Sans SC', 'M PLUS Rounded 1c', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif; }
.en-only { display: block; font-size: 11px; color: var(--ink-soft); font-style: italic; margin-top: 2px; }

/* ---------- Firefox ---------- */
/* Firefox re-blurs backdrop-filter regions whenever the WebGL globe behind
   them redraws, which is costly while the Earth spins. The glass is already
   mostly opaque, so it just drops the blur and gets a touch more opacity. */
@supports (-moz-appearance: none) {
  .glass { -webkit-backdrop-filter: none; backdrop-filter: none; background: rgba(248, 251, 255, 0.93); }
  .intro-logo { backdrop-filter: none; background: linear-gradient(180deg, rgba(40, 70, 120, 0.55), rgba(20, 40, 80, 0.45)); }
}

/* ---------- language menu ---------- */
.lang-wrap { position: relative; }
.lang {
  display: flex; align-items: center; gap: 6px; height: 42px; padding: 0 12px;
  border: 0; border-radius: 999px; font-weight: 800; font-size: 13px; color: var(--ink); transition: transform 0.15s;
}
.lang:hover { transform: translateY(-1px); }
.lang[aria-expanded="true"] { color: var(--wii-deep); }
.lang[aria-expanded="true"] .chev { transform: rotate(180deg); }
.lang .chev { color: var(--ink-soft); transition: transform 0.2s; }
.lang-short { display: none; }
.lang-menu {
  position: absolute; z-index: 20; top: calc(100% + 8px); right: 0; min-width: 190px;
  margin: 0; padding: 6px; list-style: none; border-radius: 20px;
  transform-origin: top right; animation: menu-in 0.18s cubic-bezier(.3, 1.4, .5, 1);
}
.lang-menu[hidden] { display: none; }
@keyframes menu-in { from { opacity: 0; transform: translateY(-6px) scale(0.96); } }
.lang-menu button {
  width: 100%; display: flex; align-items: center; gap: 10px; padding: 10px 14px; border: 0; border-radius: 14px;
  background: none; font-weight: 700; font-size: 15px; text-align: left; color: var(--ink);
}
.lang-menu button:hover, .lang-menu button:focus-visible { background: rgba(52, 190, 237, 0.14); outline: none; }
.lang-menu .lang-check { flex: none; color: var(--wii-deep); visibility: hidden; }
.lang-menu [aria-checked="true"] { color: var(--wii-deep); }
.lang-menu [aria-checked="true"] .lang-check { visibility: visible; }

/* ---------- explore mode ---------- */
.explore-btn {
  display: none; align-items: center; gap: 6px; margin-left: auto; padding: 6px 12px; border: 0; border-radius: 999px;
  font-weight: 800; font-size: 13px; color: #fff; background: linear-gradient(180deg, #5fd3ff, var(--wii) 50%, var(--wii-deep));
  box-shadow: 0 4px 10px -4px rgba(26, 143, 208, 0.9), inset 0 1px 0 rgba(255, 255, 255, 0.55);
}
body[data-view="globe"] .explore-btn, body[data-view="region"] .explore-btn { display: inline-flex; }
body[data-view="globe"] .panel-head, body[data-view="region"] .panel-head { align-items: center; flex-wrap: nowrap; }

body.explore .topbar { opacity: 0; transform: translateY(-16px); pointer-events: none; }
body.explore .stage { opacity: 0; transform: translateY(24px); pointer-events: none; }
body.explore .stage > * { pointer-events: none; }
body.explore .dock, body.explore .ticker { opacity: 0; transform: translateY(24px); pointer-events: none; }
body.explore .dock { transform: translate(-50%, 24px); }
.explore-exit {
  position: fixed; z-index: 30; left: 50%; bottom: max(18px, env(safe-area-inset-bottom));
  display: inline-flex; align-items: center; gap: 8px; padding: 12px 20px; border: 0; border-radius: 999px;
  font-weight: 800; font-size: 14px; color: var(--ink); transform: translateX(-50%);
  animation: exit-in 0.3s cubic-bezier(.3, 1.4, .5, 1);
}
.explore-exit[hidden] { display: none; }
@keyframes exit-in { from { opacity: 0; transform: translate(-50%, 16px); } }

@media (max-width: 860px) {
  .lang { padding: 0 10px; gap: 4px; }
  .clock { font-size: 17px; margin-right: 0; }
  .top-actions { gap: 8px; }
  .lang > svg:first-child, .lang-label { display: none; }
  .lang-short { display: inline; }
  body.explore .dock { transform: translateY(24px); }
  /* A compact Globe/Region card so more of the Earth shows above it. */
  body[data-view="globe"] .panel .hint, body[data-view="region"] .panel .hint,
  body[data-view="globe"] .panel .fine { display: none; }
  body[data-view="globe"] .panel-head, body[data-view="region"] .panel-head { padding: 10px 14px 6px; }
  body[data-view="globe"] .panel-head h1, body[data-view="region"] .panel-head h1 { font-size: 18px; }
  body[data-view="globe"] .panel-body, body[data-view="region"] .panel-body { padding: 6px 14px 12px; }
  body[data-view="globe"] .toggles { grid-template-columns: 1fr 1fr; gap: 8px; }
  body[data-view="globe"] .switch { font-size: 12px; gap: 8px; }
  .explore-btn { padding: 8px 14px; font-size: 14px; }
}

/* ---------- precipitation playback ---------- */
.anim { display: flex; align-items: center; gap: 12px; margin-top: 12px; padding: 10px 12px; border-radius: 18px; background: rgba(255, 255, 255, 0.7); box-shadow: inset 0 0 0 1px rgba(34, 50, 74, 0.06); }
.anim-play {
  flex: none; width: 40px; height: 40px; border: 0; border-radius: 50%; display: grid; place-items: center; color: #fff;
  background: linear-gradient(180deg, #5fd3ff, var(--wii) 50%, var(--wii-deep));
  box-shadow: 0 4px 10px -4px rgba(26, 143, 208, 0.9), inset 0 1px 0 rgba(255, 255, 255, 0.55); transition: transform 0.15s;
}
.anim-play:hover { transform: scale(1.06); }
.anim-rows { flex: 1; min-width: 0; display: grid; gap: 6px; }
.anim-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: 12px; }
.anim-head b { font-weight: 800; }
.anim-head span { color: var(--ink-soft); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.anim-row input[type="range"] { width: 100%; margin: 2px 0 0; accent-color: var(--wii-deep); cursor: pointer; }
.anim-row input[type="range"]:disabled { opacity: 0.4; cursor: default; }
.anim-note { margin-top: 8px; }
/* Expand/collapse for the timers; collapsed it's a single summary line. */
.anim-toggle {
  flex: none; align-self: flex-start; width: 32px; height: 32px; display: grid; place-items: center; border: 0; border-radius: 50%;
  color: var(--ink-soft); background: rgba(34, 50, 74, 0.06); transition: background 0.15s, transform 0.2s;
}
.anim-toggle:hover { background: rgba(52, 190, 237, 0.14); color: var(--wii-deep); }
.anim-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
.anim.collapsed .anim-toggle { align-self: center; }
.anim-summary { display: flex; flex-direction: column; gap: 1px; font-size: 12px; min-width: 0; }
.anim-summary b { font-weight: 800; }
.anim-summary span { color: var(--ink-soft); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 860px) {
  .anim { margin-top: 8px; padding: 8px 10px; gap: 10px; }
  .anim-play { width: 36px; height: 36px; }
  body[data-view="globe"] .toggles, body[data-view="region"] .toggles { grid-template-columns: 1fr 1fr; gap: 8px; }
  body[data-view="region"] .switch { font-size: 12px; gap: 8px; }
  body[data-view="region"] .panel .fine { display: none; }
}

/* ---------- settings ---------- */
.setting { padding: 4px 0 16px; border-bottom: 1px solid rgba(34, 50, 74, 0.1); }
.setting-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.setting-row h3 { margin: 0 0 2px; }
.setting-row .fine { margin: 0; max-width: 40ch; }
.scale-seg { flex: none; min-width: 140px; }
.scale-seg button { font-size: 15px; font-weight: 800; padding: 8px 18px; }
.scale-seg button[aria-checked="true"] { background: #fff; color: var(--wii-deep); box-shadow: 0 2px 8px rgba(0, 30, 70, 0.15); }
.about { padding-top: 4px; }
.sheet .about-title { font-size: 17px; margin: 16px 0 6px; }
.sheet h4 { font-size: 14px; margin: 14px 0 4px; }
@media (max-width: 520px) {
  .setting-row { flex-direction: column; align-items: stretch; gap: 10px; }
}

/* ---------- 1x interface size ---------- */
/* Scales the windows only. The globe, its city labels and the pick card
   stay full size, so the smaller UI simply reveals more of the Earth. */
body[data-scale="1x"] .topbar,
body[data-scale="1x"] .stage,
body[data-scale="1x"] .dock,
body[data-scale="1x"] .ticker,
body[data-scale="1x"] .explore-exit,
body[data-scale="1x"] .toast,
body[data-scale="1x"] .sheet { zoom: 0.75; }

/* ---------- full screen ---------- */
#fullscreen .fs-exit { display: none; }
body.is-fullscreen #fullscreen .fs-enter { display: none; }
body.is-fullscreen #fullscreen .fs-exit { display: block; }
#fullscreen[hidden] { display: none; }
@media (max-width: 860px) {
  .top-actions .round { width: 38px; height: 38px; }
}

/* The Earth can be dragged on every screen, not just Globe and Region. */
.globe:not([data-mode="intro"]) canvas { cursor: grab; }
.globe:not([data-mode="intro"]) canvas:active { cursor: grabbing; }
@media (max-width: 420px) {
  /* Five buttons plus the clock: keep the phone top bar inside the screen. */
  .topbar { padding-left: 12px; padding-right: 12px; }
  .top-actions { gap: 5px; }
  .top-actions .round { width: 34px; height: 34px; }
  .top-actions .round svg { width: 18px; height: 18px; }
  .lang { height: 34px; padding: 0 8px; }
  .clock { font-size: 15px; }
}

/* ---------- home-screen app ---------- */
/* Installed on iPhone the page draws under the status bar and home
   indicator (black-translucent), so keep content inside the safe area.
   In a normal browser tab these insets are all 0. */
.topbar {
  padding-top: calc(16px + env(safe-area-inset-top));
  padding-left: max(22px, env(safe-area-inset-left));
  padding-right: max(22px, env(safe-area-inset-right));
}
.ticker { height: calc(40px + env(safe-area-inset-bottom)); padding-bottom: env(safe-area-inset-bottom); }
.dock { bottom: calc(52px + env(safe-area-inset-bottom)); }
.stage { top: calc(var(--top) + env(safe-area-inset-top)); bottom: calc(var(--bottom) + env(safe-area-inset-bottom)); }
@media (max-width: 860px) {
  .topbar { padding-top: calc(12px + env(safe-area-inset-top)); padding-left: max(16px, env(safe-area-inset-left)); padding-right: max(16px, env(safe-area-inset-right)); }
  .ticker { height: calc(36px + env(safe-area-inset-bottom)); }
  .dock { bottom: calc(46px + env(safe-area-inset-bottom)); }
  .stage { top: 36vh; }
}
@media (max-width: 860px) and (max-height: 760px) { .stage { top: 30vh; } }
@media (max-width: 420px) { .topbar { padding-left: max(12px, env(safe-area-inset-left)); padding-right: max(12px, env(safe-area-inset-right)); } }
.install[hidden] { display: none; }

/* ---------- game controller ---------- */
/* Strong focus ring while navigating with the D-pad (cleared by mouse/touch). */
body.using-pad :focus { outline: 3px solid var(--wii); outline-offset: 3px; }
/* Centre marker on the Globe/Region screens: A opens the spot under it. */
.reticle {
  position: fixed; z-index: 4; left: 50%; top: 50%; width: 34px; height: 34px; margin: -17px 0 0 -17px;
  border: 2px solid rgba(255, 255, 255, 0.9); border-radius: 50%; pointer-events: none; display: none;
  box-shadow: 0 0 0 1px rgba(0, 20, 50, 0.4), inset 0 0 0 1px rgba(0, 20, 50, 0.4);
}
.reticle::after { content: ''; position: absolute; left: 50%; top: 50%; width: 4px; height: 4px; margin: -2px; border-radius: 50%; background: #fff; }
body.has-pad.started[data-view="globe"] .reticle, body.has-pad.started[data-view="region"] .reticle, body.has-pad.started.explore .reticle { display: block; }
/* Controls list in Settings, shown once a controller has connected. */
.pad-help { display: none; }
body.has-pad .pad-help { display: block; }
.pad-keys { list-style: none; padding: 0; margin: 8px 0 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 6px 16px; font-size: 13px; }
.pad-keys li { display: flex; align-items: baseline; gap: 8px; }
.pad-keys kbd { flex: none; font: inherit; font-weight: 800; font-size: 12px; padding: 2px 8px; border-radius: 8px; background: #edf1f6; color: var(--wii-deep); }
.pad-keys .pad-note { grid-column: 1 / -1; color: var(--ink-soft); font-size: 12px; }

/* ---------- data sources (Settings) ---------- */
.sources { padding: 14px 0 16px; border-bottom: 1px solid rgba(34, 50, 74, 0.1); }
.sources h3 { margin: 0 0 2px; }
.sources-list h4 { margin: 12px 0 6px; font-size: 13px; color: var(--ink-soft); text-transform: uppercase; letter-spacing: 0.04em; }
.source-row { align-items: flex-start; padding: 6px 0; }
.source-row div { display: flex; flex-direction: column; line-height: 1.3; }
.source-row small { font-weight: 500; font-size: 12px; color: var(--ink-soft); }
/* .pill sets display, which would otherwise override the hidden attribute. */
#install-btn[hidden] { display: none; }

/* ---------- phone forecast screens ---------- */
/* Compact type and icons so Now, Today and Tomorrow leave room for the globe
   above them. Only the weather icon in .day-hero is resized (not the drop). */
@media (max-width: 860px) {
  .panel-head { padding: 12px 16px 8px; gap: 2px 10px; }
  .panel-head h1 { font-size: 18px; }
  #panel-date { font-size: 12px; }
  .panel-body { padding: 12px 16px 14px; }
  .cond { font-size: 17px; line-height: 1.2; }

  .now { gap: 10px; }
  .now-icon svg { width: 76px; height: 76px; }
  .now-temp { font-size: 46px; }
  .feels { font-size: 12px; margin-top: 0; }
  .hilo-row { gap: 12px; margin-top: 4px; font-size: 12px; }
  .hilo-row b { font-size: 16px; }
  .stats { grid-template-columns: repeat(3, 1fr); gap: 6px; margin: 8px 0 0; }
  .hours { margin-top: 10px; }
  .stat { padding: 7px 8px; border-radius: 12px; }
  .stat span { font-size: 10px; }
  .stat b { font-size: 13px; }
  .hour { width: 52px; padding: 6px 2px; border-radius: 12px; }
  .hour > .wx-icon { width: 30px; height: 30px; }

  .day-hero { gap: 12px; }
  .day-hero > .wx-icon { width: 76px; height: 76px; }
  .hilo-big { font-size: 30px; gap: 10px; }
  .pop.big { font-size: 13px; margin-top: 2px; }
  .blocks { grid-template-columns: repeat(4, 1fr); gap: 6px; margin-top: 10px; }
  .block { padding: 8px 2px; border-radius: 14px; }
  .block > .wx-icon { width: 40px; height: 40px; }
  .block-label { font-size: 12px; }
  .block-range { font-size: 10px; }
  .block-temp { font-size: 17px; }
  .nws { margin-top: 10px; padding: 10px 12px; font-size: 12px; }
}

/* ---------- collapsed window (phones) ---------- */
/* A tap on the globe folds the forecast window to its title (see app.js). */
.expand-btn {
  display: none; align-items: center; gap: 4px; margin-left: auto; padding: 8px 14px; border: 0; border-radius: 999px;
  font-weight: 800; font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; color: #fff;
  background: linear-gradient(180deg, #5fd3ff, var(--wii) 50%, var(--wii-deep));
  box-shadow: 0 4px 10px -4px rgba(26, 143, 208, 0.9), inset 0 1px 0 rgba(255, 255, 255, 0.55);
}
body.collapsed .expand-btn { display: inline-flex; }
/* The folded Globe menu also keeps Explore: the two sit together on the right. */
body[data-view="globe"].collapsed .expand-btn { margin-left: 8px; }
body.collapsed .panel-body, body.collapsed #panel-date { display: none; }
body.collapsed .panel-head { align-items: center; flex-wrap: nowrap; border-bottom: 0; padding: 10px 10px 10px 16px; }
body.collapsed .panel { cursor: pointer; animation: fold-in 0.25s cubic-bezier(.3, 1.4, .5, 1); }
@keyframes fold-in { from { transform: translateY(12px); opacity: 0.6; } }

/* ---------- timeline (above the dock) ---------- */
/* The span the animation covers: earliest time at the dock's left edge,
   latest at its right, a dot gliding along (moved every frame by app.js, so
   no CSS transitions) and the time on screen in a pill in the middle, drawn
   over the line and the dot. --dock-* come from measureSafe() in app.js. */
.timeline {
  position: fixed; z-index: 8; left: var(--dock-left, 16px); width: var(--dock-width, calc(100vw - 32px));
  bottom: calc(var(--dock-top, 120px) + 8px);
  display: flex; align-items: center; gap: 10px; pointer-events: none;
  color: rgba(255, 255, 255, 0.82); font-size: 11px; font-weight: 700; letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums; white-space: nowrap; text-shadow: 0 1px 4px rgba(0, 10, 30, 0.7);
  transition: opacity 0.35s ease;
}
.timeline[hidden] { display: none; }
.tl-track { position: relative; flex: 1; height: 3px; border-radius: 3px; background: rgba(255, 255, 255, 0.25); box-shadow: 0 1px 4px rgba(0, 10, 30, 0.35); }
.tl-fill { position: absolute; inset: 0 auto 0 0; width: calc(var(--p, 0) * 100%); border-radius: inherit; background: rgba(255, 255, 255, 0.55); }
.tl-dot {
  position: absolute; top: 50%; left: calc(var(--p, 0) * 100%); width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px;
  border-radius: 50%; background: #fff; box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.22), 0 1px 4px rgba(0, 10, 30, 0.5);
}
.tl-now {
  position: absolute; z-index: 1; left: 50%; top: 50%; transform: translate(-50%, -50%);
  padding: 2px 9px; border-radius: 999px; font-weight: 800; color: #fff;
  background: rgba(10, 22, 44, 0.62); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.28);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
body:not(.started) .timeline, body.explore .timeline { opacity: 0; }
/* Leave room for it above the dock. */
body.has-timeline { --bottom: 172px; }
@media (max-width: 860px) {
  body.has-timeline { --bottom: 154px; }
}

/* ---------- My Places ---------- */
/* The star by the location chip: outlined, or filled gold once saved. */
#star-btn { flex: none; width: 46px; height: 46px; color: var(--ink-soft); }
#star-btn path { fill: none; }
#star-btn.on { color: #f5b301; }
#star-btn.on path { fill: currentColor; }

/* A phone-style list: one rounded row per place. */
.places { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.place {
  display: flex; align-items: stretch; border-radius: 18px; overflow: hidden;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.96), rgba(236, 245, 252, 0.84));
  box-shadow: inset 0 0 0 1px rgba(34, 50, 74, 0.06);
}
.place.here { box-shadow: inset 0 0 0 2px var(--wii); }
.place-open {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 12px; padding: 10px 4px 10px 12px;
  border: 0; background: none; text-align: left; transition: background 0.15s;
}
.place-open:hover { background: rgba(52, 190, 237, 0.08); }
.place-icon { flex: none; width: 44px; height: 44px; display: grid; place-items: center; }
.place-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; line-height: 1.2; }
.place-text b, .place-text small { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.place-text b { font-size: 16px; font-weight: 800; }
.place-text small { font-size: 12px; color: var(--ink-soft); }
.place-tag {
  font-style: normal; font-size: 10px; font-weight: 800; letter-spacing: 0.05em; text-transform: uppercase;
  color: var(--wii-deep); background: rgba(52, 190, 237, 0.15); padding: 1px 7px; border-radius: 999px; margin-left: 4px; vertical-align: 2px;
}
.place-temps { flex: none; display: flex; flex-direction: column; align-items: flex-end; line-height: 1.1; }
.place-temps b { font-size: 24px; font-weight: 800; }
.place-temps small { font-size: 12px; font-weight: 800; }
.place-temps .hi { color: var(--hi); }
.place-temps .lo { color: var(--lo); }
.place-star { flex: none; width: 44px; border: 0; background: none; color: #f5b301; display: grid; place-items: center; transition: background 0.15s; }
.place-star:hover { background: rgba(245, 179, 1, 0.12); }
/* Home's row: the house pin, which isn't a button (home always stays). */
.place-star.is-home, .place-star.is-home:hover { background: none; cursor: default; }
.places-empty .star { color: #f5b301; }
@media (max-width: 860px) {
  .place-open { gap: 10px; padding: 8px 2px 8px 10px; }
  .place-icon, .place-icon svg { width: 38px; height: 38px; }
  .place-temps b { font-size: 21px; }
  .place-star { width: 40px; }
}

/* ---------- Calm View ---------- */
/* The forecast laid straight onto an animated sky: no panels or borders.
   Dividers are hairlines that fade out at both ends, and the page and the
   hourly strip fade into the sky at their edges instead of being cut off. */
.calm-open-btn { width: 100%; margin-top: 12px; padding: 14px 20px; font-size: 15px; }
.calm {
  position: fixed; inset: 0; min-height: 100lvh; z-index: 35; color: #fff; background: #1b3a66;
  opacity: 0; transition: opacity 0.45s ease;
  text-shadow: 0 1px 14px rgba(0, 12, 35, 0.35);
}
.calm.open { opacity: 1; }
.calm[hidden] { display: none; }
.calm-sky { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.calm-back {
  position: absolute; z-index: 2; top: calc(14px + env(safe-area-inset-top)); left: max(14px, env(safe-area-inset-left));
  display: inline-flex; align-items: center; gap: 4px; padding: 9px 16px 9px 10px; border: 0; border-radius: 999px;
  color: #fff; font-weight: 800; font-size: 14px; background: rgba(255, 255, 255, 0.14);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); transition: background 0.15s;
}
.calm-back:hover { background: rgba(255, 255, 255, 0.24); }
.calm-body {
  position: absolute; inset: 0; overflow-y: auto; overscroll-behavior: contain; scrollbar-width: none;
  padding: calc(76px + env(safe-area-inset-top)) max(20px, env(safe-area-inset-right)) calc(48px + env(safe-area-inset-bottom)) max(20px, env(safe-area-inset-left));
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 64px, #000 calc(100% - 56px), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 64px, #000 calc(100% - 56px), transparent 100%);
}
.calm-body::-webkit-scrollbar { display: none; }
/* Sideways swipes switch places (app.js); the page itself scrolls up and down. */
.calm-body { touch-action: pan-y; }
.calm-hours { touch-action: pan-x; }

/* Previous / next place, at the sides halfway down the screen. */
.calm-arrow {
  position: absolute; z-index: 2; top: 50%; width: 44px; height: 44px; transform: translateY(-50%);
  display: grid; place-items: center; border: 0; border-radius: 50%; color: #fff; background: rgba(255, 255, 255, 0.14);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); transition: background 0.15s, transform 0.15s;
}
.calm-arrow:hover { background: rgba(255, 255, 255, 0.24); }
.calm-arrow:active { transform: translateY(-50%) scale(0.94); }
/* Centred in the space beside the 560px forecast column: that space is
   50% - 280px wide, so its middle is at 25% - 140px; less half the arrow. */
.calm-arrow.prev { left: max(6px, calc(25% - 162px), env(safe-area-inset-left)); }
.calm-arrow.next { right: max(6px, calc(25% - 162px), env(safe-area-inset-right)); }
.calm-arrow[hidden] { display: none; }
/* Phones: the text runs nearly edge to edge, so the page keeps 48px margins
   while the arrows show, and each arrow sits in the middle of its margin. */
@media (max-width: 860px) {
  .calm-arrow { width: 36px; height: 36px; }
  .calm-arrow.prev { left: max(6px, env(safe-area-inset-left)); }
  .calm-arrow.next { right: max(6px, env(safe-area-inset-right)); }
  .calm.has-arrows .calm-body { padding-left: max(48px, env(safe-area-inset-left)); padding-right: max(48px, env(safe-area-inset-right)); }
}

/* The text slides in from the side you moved toward; while the next place
   loads, the current one stays, dimmed. */
.calm-body.slide-next > * { animation: calm-from-right 0.4s cubic-bezier(.2, .8, .2, 1); }
.calm-body.slide-prev > * { animation: calm-from-left 0.4s cubic-bezier(.2, .8, .2, 1); }
@keyframes calm-from-right { from { opacity: 0; transform: translateX(36px); } }
@keyframes calm-from-left { from { opacity: 0; transform: translateX(-36px); } }
.calm-body > * { transition: opacity 0.2s; }
.calm-body.is-loading > * { opacity: 0.45; }
.calm-dots { display: flex; justify-content: center; gap: 6px; margin: 8px 0 2px; }
.calm-dots i { width: 6px; height: 6px; border-radius: 50%; background: rgba(255, 255, 255, 0.38); }
.calm-dots i.on { background: #fff; }
.calm-body > * { max-width: 560px; margin-left: auto; margin-right: auto; }

.calm-hero { text-align: center; padding: 12px 0 28px; }
.calm-hero h2 { font-size: 24px; font-weight: 700; letter-spacing: 0.01em; margin: 0; }
.calm-temp { font-size: clamp(88px, 24vw, 128px); font-weight: 400; line-height: 1; letter-spacing: -0.04em; margin: 4px 0 2px; padding-left: 0.12em; }
.calm-cond { font-size: 20px; font-weight: 700; margin: 0; }
.calm-hilo { font-size: 15px; font-weight: 500; margin: 6px 0 0; opacity: 0.88; }

.calm-sec { padding: 18px 0 20px; position: relative; }
/* A divider that melts away toward both edges. */
.calm-sec::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.4) 20%, rgba(255, 255, 255, 0.4) 80%, transparent);
}
.calm-sec h3 { margin: 0 0 12px; font-size: 12px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.75; }

.calm-hours {
  display: flex; gap: 4px; overflow-x: auto; scrollbar-width: none; padding: 2px 0;
  -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 18px, #000 calc(100% - 28px), transparent 100%);
  mask-image: linear-gradient(90deg, transparent 0, #000 18px, #000 calc(100% - 28px), transparent 100%);
}
.calm-hours::-webkit-scrollbar { display: none; }
.calm-hour { flex: none; width: 56px; display: flex; flex-direction: column; align-items: center; gap: 4px; font-size: 13px; }
.calm-hour:first-child { margin-left: 8px; }
.calm-hour > span { font-weight: 700; opacity: 0.85; }
.calm-hour b { font-size: 17px; font-weight: 700; }
.calm-pop { font-size: 11px; font-weight: 800; color: #a9dcff; }

.calm-days { list-style: none; margin: 0; padding: 0; }
.calm-days li {
  display: grid; grid-template-columns: 64px 46px 44px 1fr 44px; align-items: center; gap: 10px;
  padding: 8px 0; font-size: 17px; font-weight: 700; position: relative;
}
.calm-days li + li::before {
  content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.18) 25%, rgba(255, 255, 255, 0.18) 75%, transparent);
}
.calm-day-icon { display: flex; flex-direction: column; align-items: center; line-height: 1; }
.calm-lo { text-align: right; opacity: 0.7; }
.calm-hi { text-align: left; }
.calm-range { position: relative; height: 5px; border-radius: 5px; background: rgba(255, 255, 255, 0.18); }
.calm-range i { position: absolute; top: 0; bottom: 0; border-radius: 5px; background: linear-gradient(90deg, #8fd0ff, #ffe08a, #ff9d6b); }

.calm-details { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px 12px; }
.calm-details span { display: block; font-size: 11px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; opacity: 0.72; margin-bottom: 3px; }
.calm-details b { font-size: 18px; font-weight: 700; }
@media (max-width: 420px) {
  .calm-days li { grid-template-columns: 52px 40px 40px 1fr 40px; gap: 8px; font-size: 16px; }
  .calm-details { grid-template-columns: repeat(2, 1fr); }
}
