/* ============================================================
   What the Wether V19 — styles.css
   All colors come from CSS variables so themes are one block
   each. Default theme: Neon Dark. Others: Midnight, Light.
   ============================================================ */

/* ---------------- Theme variables ---------------- */

:root,
[data-theme="neon-dark"] {
  --bg: #0a0e17;
  --bg-2: #0e1524;
  --card: rgba(18, 26, 43, 0.92);
  --card-border: rgba(0, 255, 157, 0.18);
  --text: #e8f6ff;
  --text-dim: #8ba3b8;
  --accent: #00ff9d;
  --accent-contrast: #04120b;
  --accent-2: #00c8ff;
  --danger: #ff5470;
  --input-bg: rgba(8, 13, 24, 0.9);
  --input-border: rgba(0, 200, 255, 0.25);
  --btn-bg: rgba(0, 200, 255, 0.1);
  --btn-border: rgba(0, 200, 255, 0.35);
  --btn-hover: rgba(0, 255, 157, 0.18);
  --shadow: 0 10px 34px rgba(0, 0, 0, 0.5);
  --glow: 0 0 18px rgba(0, 255, 157, 0.35);
  --radar-accent: #00ff9d;
  --radar-ring: rgba(0, 255, 157, 0.25);
  --radar-bg-1: #02100a;
  --radar-bg-2: #05261b;
  --header-grad: linear-gradient(135deg, rgba(0,255,157,0.08), rgba(0,200,255,0.08));
}

[data-theme="midnight"] {
  --bg: #05060f;
  --bg-2: #0a0c1c;
  --card: rgba(13, 16, 34, 0.95);
  --card-border: rgba(122, 92, 255, 0.25);
  --text: #e6e4ff;
  --text-dim: #9a95c4;
  --accent: #8f6bff;
  --accent-contrast: #0e0722;
  --accent-2: #4f7cff;
  --danger: #ff5470;
  --input-bg: rgba(6, 7, 18, 0.95);
  --input-border: rgba(122, 92, 255, 0.3);
  --btn-bg: rgba(122, 92, 255, 0.12);
  --btn-border: rgba(122, 92, 255, 0.4);
  --btn-hover: rgba(143, 107, 255, 0.22);
  --shadow: 0 10px 34px rgba(0, 0, 0, 0.65);
  --glow: 0 0 18px rgba(143, 107, 255, 0.4);
  --radar-accent: #8f6bff;
  --radar-ring: rgba(143, 107, 255, 0.28);
  --radar-bg-1: #070312;
  --radar-bg-2: #140b2e;
  --header-grad: linear-gradient(135deg, rgba(143,107,255,0.1), rgba(79,124,255,0.08));
}

[data-theme="light"] {
  --bg: #eef3f9;
  --bg-2: #e2eaf4;
  --card: rgba(255, 255, 255, 0.94);
  --card-border: rgba(20, 90, 160, 0.16);
  --text: #17222e;
  --text-dim: #5d7185;
  --accent: #0a84d0;
  --accent-contrast: #ffffff;
  --accent-2: #0abf8a;
  --danger: #d63552;
  --input-bg: #ffffff;
  --input-border: rgba(20, 90, 160, 0.3);
  --btn-bg: rgba(10, 132, 208, 0.08);
  --btn-border: rgba(10, 132, 208, 0.3);
  --btn-hover: rgba(10, 132, 208, 0.16);
  --shadow: 0 8px 26px rgba(30, 60, 90, 0.14);
  --glow: 0 0 14px rgba(10, 132, 208, 0.25);
  --radar-accent: #0a84d0;
  --radar-ring: rgba(10, 132, 208, 0.25);
  --radar-bg-1: #dcebf7;
  --radar-bg-2: #c2ddf2;
  --header-grad: linear-gradient(135deg, rgba(10,132,208,0.08), rgba(10,191,138,0.08));
}

/* ---------------- Base ---------------- */

* { box-sizing: border-box; margin: 0; padding: 0; }

/* The hidden attribute must win over component display rules. */
[hidden] { display: none !important; }

html { height: 100%; }

body {
  min-height: 100%;
  font-family: 'Segoe UI', system-ui, -apple-system, Roboto, Helvetica, Arial, sans-serif;
  background: radial-gradient(1200px 700px at 80% -10%, var(--bg-2), transparent 60%), var(--bg);
  color: var(--text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  padding-bottom: env(safe-area-inset-bottom);
  transition: background 0.35s ease, color 0.35s ease;
}

a { color: var(--accent-2); }

button { font: inherit; cursor: pointer; }
input, select { font: inherit; color: var(--text); }

body.loading { cursor: progress; }


/* ============================================================
   The sky, and the knobs that change how everything looks.

   Two independent things are set on the root element:

     data-sky / data-daynight  — what the weather is doing, which
       picks the page's own colours. Set by weatheranim.js at the same
       moment it points the canvas at a new scene, so the colour and
       the animation can never show different weather.

     data-cards / data-corners / data-density — the user's own
       choices, which change how every card and tile is drawn without
       touching a single component's rules.

   Everything reads --sky-1 / --sky-2 / --sky-ink, so a new sky is one
   block here and nothing else.
   ============================================================ */

:root {
  --sky-1: var(--bg-2);
  --sky-2: var(--bg);
  --sky-ink: var(--text);
  --tile-bg: var(--card);
  --tile-border: var(--card-border);
  --tile-radius: 18px;
  --tile-pad: 1rem 1.1rem;
  --tile-gap: 0.7rem;
}

/* ---- Clear ---- */
[data-sky="clear"][data-daynight="day"] {
  --sky-1: #2f7cc4;
  --sky-2: #7fbde8;
}
[data-sky="clear"][data-daynight="night"] {
  --sky-1: #0b1a3a;
  --sky-2: #1d2f5c;
}

/* ---- Cloud ---- */
[data-sky="clouds"][data-daynight="day"] {
  --sky-1: #47708f;
  --sky-2: #8ea7bd;
}
[data-sky="clouds"][data-daynight="night"] {
  --sky-1: #101a2e;
  --sky-2: #26344c;
}

/* ---- Rain ---- */
[data-sky="rain"][data-daynight="day"] {
  --sky-1: #2f4b6b;
  --sky-2: #5e7a96;
}
[data-sky="rain"][data-daynight="night"] {
  --sky-1: #0a1424;
  --sky-2: #1c2c43;
}

/* ---- Storm ---- */
[data-sky="storm"][data-daynight="day"] {
  --sky-1: #363f5c;
  --sky-2: #5a6480;
}
[data-sky="storm"][data-daynight="night"] {
  --sky-1: #080b16;
  --sky-2: #1b2036;
}

/* ---- Snow and sleet ---- */
[data-sky="snow"][data-daynight="day"],
[data-sky="sleet"][data-daynight="day"] {
  --sky-1: #52748f;
  --sky-2: #a2b8cc;
}
[data-sky="snow"][data-daynight="night"],
[data-sky="sleet"][data-daynight="night"] {
  --sky-1: #101c30;
  --sky-2: #2b3b53;
}

/* ---- Fog ---- */
[data-sky="fog"][data-daynight="day"] {
  --sky-1: #5f6975;
  --sky-2: #9aa3ad;
}
[data-sky="fog"][data-daynight="night"] {
  --sky-1: #14181f;
  --sky-2: #2c333d;
}

/* Ink over a sky.

   This is the part that decides whether the app is readable. The dark
   themes' dimmed text was tuned against a near-black page; over a
   mid-blue sky at midday it disappears, and a label nobody can read
   is worse than no label. So with a sky behind it, the text switches
   to white with real opacity steps — which is exactly why Apple's
   Weather is white-on-sky and not grey-on-sky.

   The light theme keeps dark ink and dims the sky instead: pale text
   on a pale sky fails the same way in the other direction. */
[data-sky]:not([data-sky="none"]) {
  --text: #ffffff;
  --text-dim: rgba(255, 255, 255, 0.9);
  --card-border: rgba(255, 255, 255, 0.18);
}
[data-theme="light"][data-sky]:not([data-sky="none"]) {
  --text: #10202e;
  --text-dim: rgba(16, 32, 46, 0.66);
  --card-border: rgba(16, 32, 46, 0.14);
}
[data-theme="light"] .sky-backdrop { opacity: 0.45; }

/* Turning the background off returns the page to the plain theme. */
[data-sky="none"] .sky-backdrop { display: none; }

.sky-backdrop {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(180deg, var(--sky-1), var(--sky-2));
  transition: background 0.8s ease;
}
.sky-backdrop canvas { display: block; width: 100%; height: 100%; }

/* The header sits on the sky like everything else, rather than
   punching an opaque bar through it. It keeps the blur — sticky
   translucent text over moving rain is unreadable without one. */
[data-sky]:not([data-sky="none"]) .app-header {
  background: rgba(9, 20, 38, 0.42);
  border-bottom-color: rgba(255, 255, 255, 0.14);
}
[data-theme="light"][data-sky]:not([data-sky="none"]) .app-header {
  background: rgba(255, 255, 255, 0.6);
  border-bottom-color: rgba(16, 32, 46, 0.12);
}

/* The panels that had their own dark ground — the search box, the
   nowcast strip, the roast — would otherwise punch opaque holes in
   the sky. They take the same glass as everything else, and keep
   their own borders so they still read as separate things. */
[data-sky]:not([data-sky="none"]) input[type="text"],
[data-sky]:not([data-sky="none"]) input[type="password"],
[data-sky]:not([data-sky="none"]) input[type="search"],
[data-sky]:not([data-sky="none"]) select {
  background: rgba(9, 20, 38, 0.4);
  border-color: rgba(255, 255, 255, 0.16);
  color: var(--text);
}

/* The bot and the nowcast belong to the card they sit in.

   They had their own dark ground, which put a box inside a box: a
   panel of one shade of glass floating on a card of another, for
   content that is part of that card's story. They keep a hairline
   above them to separate the sections and nothing else. */
[data-sky]:not([data-sky="none"]) .roast-inline,
[data-sky]:not([data-sky="none"]) .nowcast-panel {
  background: none;
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.14);
  padding-left: 0;
  padding-right: 0;
  color: var(--text);
}
[data-theme="light"][data-sky]:not([data-sky="none"]) input[type="text"],
[data-theme="light"][data-sky]:not([data-sky="none"]) input[type="password"],
[data-theme="light"][data-sky]:not([data-sky="none"]) input[type="search"],
[data-theme="light"][data-sky]:not([data-sky="none"]) select {
  background: rgba(255, 255, 255, 0.6);
  border-color: rgba(16, 32, 46, 0.12);
}
[data-theme="light"][data-sky]:not([data-sky="none"]) .roast-inline,
[data-theme="light"][data-sky]:not([data-sky="none"]) .nowcast-panel {
  border-top-color: rgba(16, 32, 46, 0.14);
}
[data-sky]:not([data-sky="none"]) ::placeholder { color: var(--text-dim); }

/* With a sky behind it, the page's own ground would hide it. */
[data-sky]:not([data-sky="none"]) body { background: transparent; }

/* ---------------- Card style ---------------- */

/* Glass is the default and the one that suits a sky behind it.
   Solid is for anybody who finds translucency hard to read, and
   outline is for people who want the sky and nothing in its way. */
[data-cards="glass"] {
  /* Darkening, not lightening. A white-tinted tile under white text
     over a midday sky measures about 1.5:1 — the text is there and
     nobody can read it. Tinting down puts the same glass at 5:1 and
     is what Apple's Weather actually does behind its white type. */
  --tile-bg: rgba(9, 20, 38, 0.52);
  --tile-border: rgba(255, 255, 255, 0.16);
}
[data-cards="glass"] .card,
[data-cards="glass"] .tile {
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
}
[data-cards="glass"] .card {
  background: rgba(9, 20, 38, 0.48);
  border-color: rgba(255, 255, 255, 0.14);
}
[data-theme="light"][data-cards="glass"] {
  --tile-bg: rgba(255, 255, 255, 0.72);
  --tile-border: rgba(0, 0, 0, 0.1);
}
[data-theme="light"][data-cards="glass"] .card {
  background: rgba(255, 255, 255, 0.75);
  border-color: rgba(0, 0, 0, 0.08);
}

[data-cards="solid"] {
  --tile-bg: var(--card);
  --tile-border: var(--card-border);
}
[data-cards="solid"] .card { background: var(--card); }

[data-cards="outline"] {
  --tile-bg: transparent;
  --tile-border: currentColor;
}
[data-cards="outline"] .card {
  background: transparent;
  border-color: var(--card-border);
  box-shadow: none;
}
[data-cards="outline"] .tile { box-shadow: none; }

/* ---------------- Corners ---------------- */

[data-corners="round"] { --tile-radius: 22px; }
[data-corners="soft"]  { --tile-radius: 12px; }
[data-corners="square"] { --tile-radius: 3px; }
[data-corners="round"] .card { border-radius: 22px; }
[data-corners="soft"] .card { border-radius: 12px; }
[data-corners="square"] .card { border-radius: 3px; }

/* ---------------- Density ---------------- */

[data-density="compact"] {
  --tile-pad: 0.7rem 0.8rem;
  --tile-gap: 0.5rem;
}
[data-density="airy"] {
  --tile-pad: 1.35rem 1.4rem;
  --tile-gap: 1rem;
}

/* ============================================================
   The detail tiles
   ============================================================ */

.tile-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--tile-gap);
  margin: 1rem 0 0.4rem;
}

.tile {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  background: var(--tile-bg);
  border: 1px solid var(--tile-border);
  border-radius: var(--tile-radius);
  padding: var(--tile-pad);
  min-height: 128px;
}
[data-density="compact"] .tile { min-height: 104px; }

.tile-head {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.9px;
  text-transform: uppercase;
  color: var(--text-dim);
  margin: 0;
}
.tile-head .ui-icon { opacity: 0.85; }

.tile-value {
  font-size: clamp(1.6rem, 5vw, 2.1rem);
  font-weight: 300;
  letter-spacing: -0.5px;
  line-height: 1.1;
  margin: 0.1rem 0 0;
}
.tile-word { font-size: 1rem; font-weight: 600; margin: -0.15rem 0 0; }
.tile-note {
  font-size: 0.82rem;
  color: var(--text-dim);
  margin: auto 0 0;
  line-height: 1.35;
}

/* The one tile that does something when tapped says so. */
.tile-action { cursor: pointer; }
.tile-action:hover { border-color: var(--accent); }
.tile-action:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Sheets whose facts are a table rather than a curve. */
.sheet-rows { margin: 0.4rem 0 0; font-size: 0.95rem; }
.sheet-rows > div {
  display: flex;
  justify-content: space-between;
  gap: 0.8rem;
  padding: 0.55rem 0;
  border-bottom: 1px solid var(--card-border);
}
.sheet-rows > div:last-child { border-bottom: 0; }
.sheet-rows dt { color: var(--text-dim); }
.sheet-rows dd { margin: 0; font-weight: 600; text-align: right; }

/* ---------------- Radar controls ---------------- */

/* The wall-clock time of the frame on screen. The timeline label says
   NOW or +20 min, which is a relation; this is the time. */
.frame-clock {
  font-size: 0.72rem;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  letter-spacing: 0.4px;
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  white-space: nowrap;
}
.frame-clock[data-kind="forecast"] { color: var(--accent-2); border-color: var(--accent-2); }

.radar-sliders {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 0.6rem;
}
.radar-slider {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: 1 1 200px;
  min-width: 0;
  font-size: 0.76rem;
  color: var(--text-dim);
}
.radar-slider > span { flex: 0 0 auto; white-space: nowrap; }
.radar-slider input[type="range"] { flex: 1 1 auto; min-width: 0; }
.radar-slider output {
  flex: 0 0 3ch;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* The UV bar: the published 0–11+ scale, with a dot at the reading. */
.tile-scale {
  position: relative;
  height: 5px;
  border-radius: 999px;
  margin: 0.3rem 0 0.1rem;
}
.uv-scale {
  background: linear-gradient(90deg, #4ade80 0%, #facc15 32%, #fb923c 52%,
                                     #ef4444 72%, #d946ef 100%);
}
.tile-scale-dot {
  position: absolute;
  top: 50%;
  width: 10px; height: 10px;
  margin-left: -5px;
  border-radius: 50%;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.25);
  transform: translateY(-50%);
  transition: left 0.4s ease;
}
.tile-scale-ends {
  display: flex;
  justify-content: space-between;
  font-size: 0.75rem;
  color: var(--text-dim);
  margin: 0;
}

/* A second, quieter line under a tile's sentence: the chance under an
   amount, the gusts under the steady wind. Secondary by design — if
   it were the headline it would be the value. */
.tile-sub {
  font-size: 0.78rem;
  color: var(--text-dim);
  margin: 0.15rem 0 0;
  opacity: 0.85;
}

.avg-facts { margin: auto 0 0.2rem; font-size: 0.85rem; }
.avg-facts > div {
  display: flex;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.15rem 0;
}
.avg-facts dt { color: var(--text-dim); }
.avg-facts dd { margin: 0; font-weight: 700; font-variant-numeric: tabular-nums; }

/* The sentence over the hour row. */
.hourly-summary {
  margin: 0 0 0.8rem;
  font-size: 0.92rem;
  line-height: 1.4;
}

/* Where the forecast is actually for. */
.place-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  flex-wrap: wrap;
  margin-top: 0.8rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--card-border);
}
.place-lines { display: flex; flex-direction: column; min-width: 0; }
.place-lines strong { font-size: 0.95rem; }
.place-coords {
  font-size: 0.8rem;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
#openInMaps { text-decoration: none; flex: 0 0 auto; }

/* Which brain wrote the line. It matters that this is visible: "the
   model said it" and "a template said it" are different claims. */
.roast-brain {
  font-size: 0.68rem;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  padding: 0.1rem 0.45rem;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  color: var(--text-dim);
  white-space: nowrap;
}
.roast-brain[data-brain="gemini"] { color: var(--accent); border-color: var(--accent); }
.roast-brain[data-brain="thinking"] { opacity: 0.7; }
.roast-brain[data-brain="badkey"] { color: var(--danger); border-color: var(--danger); }

/* Settings rows that pair a field with a button. */
.setting-row {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 0.35rem;
}
.setting-row input { flex: 1 1 12rem; min-width: 0; }

.setting-status {
  font-size: 0.82rem;
  margin: 0.5rem 0 0;
  line-height: 1.4;
}
.setting-status[data-kind="ok"] { color: var(--accent); }
.setting-status[data-kind="warn"] { color: var(--danger); }

/* The part about where the key lives. Worth reading, so it is not the
   same grey as every other hint. */
.setting-warn {
  border-left: 2px solid var(--danger);
  padding-left: 0.6rem;
  margin-top: 0.6rem;
}

/* ============================================================
   The metric sheet
   ============================================================ */

.metric-sheet { width: min(620px, calc(100vw - 2rem)); }

/* The date strip. Seven buttons, the open one marked — and marked by
   more than colour, since colour alone is not a marker to everyone. */
.sheet-dates {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 0.25rem;
  margin: 0.7rem 0 0.4rem;
}
.sheet-date {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  padding: 0.35rem 0.1rem;
  background: none;
  border: 0;
  border-radius: 999px;
  color: var(--text-dim);
  font: inherit;
}
.sheet-dow { font-size: 0.68rem; letter-spacing: 0.5px; }
.sheet-dom {
  font-size: 0.95rem;
  font-variant-numeric: tabular-nums;
  width: 1.9em;
  height: 1.9em;
  display: grid;
  place-items: center;
  border-radius: 50%;
}
.sheet-date.picked { color: var(--text); font-weight: 700; }
.sheet-date.picked .sheet-dom { background: var(--accent); color: var(--accent-contrast); }
.sheet-date:hover .sheet-dom { outline: 1px solid var(--card-border); }
.sheet-date:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.sheet-value {
  font-size: clamp(2rem, 8vw, 2.8rem);
  font-weight: 300;
  letter-spacing: -1px;
  margin: 0.5rem 0 0;
}
.sheet-sub { color: var(--text-dim); font-size: 0.85rem; margin: 0.1rem 0 0.2rem; }

.sheet-legend { display: flex; gap: 0.9rem; margin: 0.3rem 0 0; font-size: 0.78rem; }
.sheet-key { display: inline-flex; align-items: center; gap: 0.35rem; color: var(--text-dim); }
.sheet-key::before {
  content: '';
  width: 14px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
}
.sheet-key-main { color: var(--accent); }
.sheet-key-alt { color: var(--accent-2); }

.sheet-chart-wrap { position: relative; margin-top: 0.6rem; }
.sheet-chart-wrap canvas { display: block; width: 100%; }
.sheet-empty {
  margin: 0;
  padding: 2rem 0;
  text-align: center;
  color: var(--text-dim);
  font-size: 0.88rem;
}
.sheet-summary {
  margin: 0.8rem 0 0;
  font-size: 0.92rem;
  line-height: 1.45;
  color: var(--text);
}

/* Wind's three facts. */
.wind-facts { margin: 0.2rem 0 0; font-size: 0.9rem; }
.wind-facts > div {
  display: flex;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.12rem 0;
}
.wind-facts dt { color: var(--text-dim); }
.wind-facts dd { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }

/* A tile that opens something says so on hover and on focus. */
.tile-action { cursor: pointer; }
.tile-action:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.wind-dial { margin: auto 0 0.1rem; align-self: center; width: 74px; }
.wind-dial-svg { display: block; width: 100%; height: auto; }
.wind-dial-ring { fill: none; stroke: currentColor; stroke-opacity: 0.35; stroke-width: 2; }
.wind-dial-n { fill: currentColor; font-size: 12px; text-anchor: middle; opacity: 0.75; }
.wind-dial-arrow { fill: currentColor; }
#windArrow { transition: transform 0.5s ease; }

.sun-arc-wrap, .pressure-dial { margin-top: auto; }
.sun-arc-wrap canvas, .pressure-dial canvas { display: block; width: 100%; }
.tile-value-dial { margin-top: -0.2rem; }

.moon-tile-body { display: flex; align-items: center; gap: 0.9rem; }
.moon-facts { flex: 1; min-width: 0; margin: 0; font-size: 0.9rem; }
.moon-facts > div {
  display: flex;
  justify-content: space-between;
  gap: 0.6rem;
  padding: 0.28rem 0;
  border-bottom: 1px solid var(--tile-border);
}
.moon-facts > div:last-child { border-bottom: 0; }
.moon-facts dt { color: var(--text-dim); white-space: nowrap; }
.moon-facts dd { margin: 0; font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 600; }
.moon-disc-wrap { flex: 0 0 84px; width: 84px; }
.moon-disc-wrap canvas { display: block; width: 100%; }

/* A tile that always wants the full row. On a phone the moon's three
   facts and its disc simply do not fit in half of one. */
.tile-wide { grid-column: 1 / -1; }

/* The AQI scale runs Good → Hazardous, the same order the published
   bands do, so a dot two-thirds along means something. */
.aqi-scale {
  background: linear-gradient(90deg, #4ade80 0%, #facc15 17%, #fb923c 33%,
                                     #ef4444 50%, #a855f7 67%, #7f1d1d 100%);
}
[data-tile="aqi"] .aqi-badge {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  box-shadow: none;
  width: auto;
  height: auto;
  display: inline;
}

/* ============================================================
   The hero

   Not a card. It is the sky's own weather, and a border round it
   makes the background read as wallpaper behind a window rather
   than as the thing being reported.
   ============================================================ */

.hero {
  text-align: center;
  padding: 1.6rem 1rem 0.6rem;
}
.hero-city {
  font-size: 1.6rem;
  font-weight: 500;
  letter-spacing: 0.2px;
  margin: 0 0 0.1rem;
}
.hero .wx-temp { font-weight: 200; }
.hero-actions {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 0.9rem;
}

/* Over a sky, type needs a little separation from whatever is moving
   behind it — a shadow does that without a box. */
[data-sky]:not([data-sky="none"]) .hero {
  text-shadow: 0 1px 14px rgba(0, 0, 0, 0.35);
}

/* ============================================================
   The hour row
   ============================================================ */

.hour-strip-wrap {
  overflow-x: auto;
  overflow-y: hidden;
  margin: 0 -0.4rem 0.9rem;
  padding: 0 0.4rem 0.35rem;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.hour-strip {
  display: flex;
  gap: 0.15rem;
  list-style: none;
  margin: 0;
  padding: 0;
  min-width: min-content;
}
.hour-cell {
  flex: 0 0 auto;
  width: 62px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  padding: 0.55rem 0.2rem;
  border-radius: calc(var(--tile-radius) * 0.7);
  text-align: center;
}
.hour-label {
  font-size: 0.76rem;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.hour-art { line-height: 0; min-height: 30px; display: flex; align-items: center; }
.hour-temp {
  font-size: 1.05rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.hour-pop {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--accent-2);
  line-height: 1;
}
/* "Now" is the one people look for first. */
.hour-now { background: var(--tile-bg); }
.hour-now .hour-label { color: var(--text); font-weight: 700; }
/* Sunrise and sunset read as markers, not as hours with a temperature. */
.hour-event .hour-temp { font-size: 0.78rem; font-weight: 500; color: var(--text-dim); }
.hour-event .ui-icon { opacity: 0.9; }

/* ---------------- Buttons ---------------- */

.btn {
  background: var(--btn-bg);
  border: 1px solid var(--btn-border);
  color: var(--text);
  border-radius: 10px;
  padding: 0.55rem 0.9rem;
  min-height: 42px;
  transition: background 0.15s ease, transform 0.1s ease, box-shadow 0.15s ease;
  touch-action: manipulation;
}
.btn:hover { background: var(--btn-hover); box-shadow: var(--glow); }
.btn:active { transform: scale(0.97); }
.btn:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; }

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-contrast);
  font-weight: 700;
}
.btn-primary:hover { filter: brightness(1.1); background: var(--accent); }

.btn-small { padding: 0.35rem 0.65rem; min-height: 34px; font-size: 0.85rem; }

/* Header actions: deliberately smaller than body buttons, but still
   above the 32px comfortable-tap floor. */
.btn-compact {
  padding: 0.3rem 0.6rem;
  min-height: 34px;
  font-size: 0.82rem;
  border-radius: 9px;
}

.btn.saved { background: var(--accent); color: var(--accent-contrast); border-color: var(--accent); }

/* Interface icons inside buttons and headings.

   Emoji rendered at whatever size and colour the platform felt like,
   and sat on the baseline rather than beside the label. These are
   drawn in the button's own colour and centred against the text, so a
   primary button, a quiet button and a heading all look deliberate.

   The button becomes a flex row so the icon and the label share a
   baseline-independent centre line; buttons with no label are simply
   a one-item row and stay square. */
.btn, .card-head h2, .settings-head h2, .temp-modal-head h2 {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  justify-content: center;
}
.card-head h2, .settings-head h2, .temp-modal-head h2 { justify-content: flex-start; }

.btn-ico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.ui-icon {
  display: block;
  overflow: visible;
  /* Strokes are drawn in the inherited colour, so an icon on a primary
     button is the contrast colour without a second rule. */
  color: inherit;
}
.btn-primary .ui-icon { opacity: 1; }
.btn .ui-icon { opacity: 0.92; }
.btn:hover .ui-icon { opacity: 1; }

/* The account button carries either an icon, a chosen picture emoji,
   or an initial — all three want the same box. */
#accountBtnIcon { min-width: 1.15em; text-align: center; font-size: 1rem; line-height: 1; }

/* ---------------- Accessibility helpers ---------------- */

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: 0.5rem;
  top: -3rem;
  z-index: 200;
  background: var(--accent);
  color: var(--accent-contrast);
  font-weight: 700;
  padding: 0.5rem 0.9rem;
  border-radius: 0 0 10px 10px;
  transition: top 0.15s ease;
}
.skip-link:focus { top: 0; }

/* ---------------- Search results ---------------- */

.search-field { position: relative; flex: 1; min-width: 0; }
.search-field input { width: 100%; }

.search-results {
  position: absolute;
  top: calc(100% + 0.35rem);
  left: 0;
  right: 0;
  z-index: 60;
  list-style: none;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  box-shadow: var(--shadow);
  overflow: hidden auto;
  max-height: 60vh;
}
.search-heading {
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: var(--text-dim);
  padding: 0.5rem 0.9rem 0.2rem;
}
.search-result {
  padding: 0.6rem 0.9rem;
  cursor: pointer;
  font-size: 0.92rem;
  border-top: 1px solid transparent;
}
.search-result:hover,
.search-result.active {
  background: var(--btn-hover);
  color: var(--text);
}

/* ---------------- Header ---------------- */

.app-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 1rem 1.25rem;
  background: var(--header-grad), var(--card);
  border-bottom: 1px solid var(--card-border);
  position: sticky;
  top: 0;
  z-index: 40;
  backdrop-filter: blur(10px);
}

.brand { display: flex; align-items: center; gap: 0.8rem; min-width: 0; }
.brand-logo { width: 52px; height: 52px; filter: drop-shadow(var(--glow)); }
.brand-text h1 { font-size: 1.35rem; letter-spacing: 0.5px; white-space: nowrap; }
.brand-greeting { color: var(--text-dim); font-size: 0.85rem; }
.brand-greeting strong { color: var(--accent); }

.sticky-weather {
  display: none;
  align-items: baseline;
  gap: 0.65rem;
  min-width: 0;
}
.sticky-weather-city {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 1rem;
  font-weight: 750;
}
.sticky-weather-temp {
  flex: 0 0 auto;
  color: var(--accent);
  font-size: 1.35rem;
  font-weight: 800;
  text-shadow: var(--glow);
}

/* Once the hero has scrolled behind the sticky header, keep the two
   facts people most often glance back for without occupying hero-sized
   space. Search and the primary controls remain reachable. */
.app-header.header-condensed { padding-block: 0.55rem; }
.app-header.header-condensed .brand-logo,
.app-header.header-condensed .brand-text,
.app-header.header-condensed .search-field { display: none; }
.app-header.header-condensed .sticky-weather { display: flex; }
.app-header.header-condensed .header-tools { flex-basis: auto; }

.version-badge {
  display: inline-block;
  background: var(--accent);
  color: var(--accent-contrast);
  font-size: 0.7rem;
  font-weight: 800;
  border-radius: 6px;
  padding: 0.1rem 0.45rem;
  vertical-align: middle;
  box-shadow: var(--glow);
}

/* Actions on top, search directly beneath them. */
.header-tools {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  flex: 1 1 340px;
  max-width: 620px;
  min-width: 0;
}
.tool-row {
  display: flex;
  gap: 0.4rem;
  justify-content: flex-end;
  flex-wrap: wrap;
}
.header-tools input {
  width: 100%;
  min-width: 0;
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: 10px;
  padding: 0.5rem 0.85rem;
  min-height: 40px;
  outline: none;
}
.header-tools input:focus { border-color: var(--accent); box-shadow: var(--glow); }

/* ---------------- Welcome panel ---------------- */

.welcome-panel {
  max-width: 560px;
  margin: 12vh auto 0;
  text-align: center;
  padding: 2rem 1.25rem;
}
.welcome-logo { width: 110px; height: 110px; filter: drop-shadow(var(--glow)); animation: floaty 4s ease-in-out infinite; }
.welcome-panel h2 { margin: 1rem 0 0.5rem; font-size: 1.6rem; }
.welcome-panel p { color: var(--text-dim); }
.welcome-actions { display: flex; gap: 0.75rem; justify-content: center; margin-top: 1.25rem; flex-wrap: wrap; }

@keyframes floaty {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}

/* ---------------- Main grid ---------------- */

.app-main {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  /* Reading order, not drawing order. What people came for goes
     first: where they are and what it is doing, then the next few
     hours, then the week — and only then the detail, the scope and
     the rest. The hero spans both columns because it is the sky, not
     a card sitting in a column. */
  grid-template-areas:
    "alerts   alerts"
    "hero     hero"
    "hourly   hourly"
    "forecast radar"
    "current  current"
    "air      compare"
    "favorites favorites";
  gap: 1.1rem;
  padding: 1.25rem;
  max-width: 1200px;
  margin: 0 auto;
  /* Cards size to their content instead of stretching to match the
     tallest in the row, so the weather card doesn't trail dead space
     under the roast. */
  align-items: start;
}

.hero { grid-area: hero; }
.current-card { grid-area: current; }
.radar-card { grid-area: radar; }
.hourly-card { grid-area: hourly; }
.air-card { grid-area: air; }
.compare-card { grid-area: compare; }
.forecast-card-panel { grid-area: forecast; }
.favorites-card { grid-area: favorites; }

/* ---------------- Cards ---------------- */

.card {
  min-width: 0; /* let grid items shrink below their content width */
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 16px;
  padding: 1.1rem 1.2rem;
  box-shadow: var(--shadow);
}

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.8rem;
  flex-wrap: wrap;
}
.card-head h2 { font-size: 1.05rem; letter-spacing: 0.4px; }
.card-head-actions { display: flex; gap: 0.4rem; flex-wrap: wrap; }

/* ---------------- Current weather ---------------- */

.current-main { display: flex; align-items: center; gap: 1.2rem; margin: 0.4rem 0 1rem; }
.wx-icon { font-size: 4rem; line-height: 1; filter: drop-shadow(var(--glow)); }
.wx-temp { font-size: 3.4rem; font-weight: 800; line-height: 1; text-shadow: var(--glow); }
.wx-condition { color: var(--text-dim); margin-top: 0.3rem; font-size: 1.05rem; }

.wx-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 0.6rem;
}
.stat {
  background: var(--input-bg);
  border: 1px solid var(--card-border);
  border-radius: 10px;
  padding: 0.5rem 0.7rem;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.stat-label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.8px; color: var(--text-dim); }
.stat-value { font-weight: 700; font-size: 1.05rem; }

.wx-updated { margin-top: 0.7rem; font-size: 0.75rem; color: var(--text-dim); }

/* ---------------- Built-in roast ---------------- */

.roast-inline {
  margin-top: 1rem;
  padding-top: 0.9rem;
  border-top: 1px dashed var(--card-border);
}
.roast-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 0.4rem;
}
.roast-label { font-weight: 800; font-size: 0.95rem; letter-spacing: 0.3px; }
.roast-meta { display: inline-flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.roast-context {
  font-size: 0.7rem;
  color: var(--text-dim);
  border: 1px solid var(--card-border);
  border-radius: 999px;
  padding: 0.1rem 0.55rem;
}
.roast-actions { display: flex; gap: 0.5rem; }
.roast-actions .btn { flex: 1; }
.roast-actions .btn-primary { flex: 2; }

.roast-log-toggle {
  margin-top: 0.7rem;
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 0.78rem;
  padding: 0.2rem 0;
}
.roast-log-toggle:hover { color: var(--accent); }
.roast-log-panel {
  margin-top: 0.4rem;
  max-height: 220px;
  overflow-y: auto;
  border: 1px solid var(--card-border);
  border-radius: 10px;
  background: var(--input-bg);
  padding: 0.5rem 0.7rem;
}
.roast-log-list { list-style: none; display: flex; flex-direction: column; gap: 0.6rem; }
.roast-log-item { font-size: 0.85rem; }
.roast-log-meta {
  font-size: 0.66rem;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.5px;
  margin-bottom: 0.1rem;
}
.roast-log-empty { color: var(--text-dim); font-size: 0.82rem; }
.roast-personality {
  font-size: 0.75rem;
  color: var(--accent);
  border: 1px solid var(--btn-border);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
}
.roast-text {
  font-size: 1.05rem;
  margin: 0.3rem 0 0.9rem;
  min-height: 3em;
}
.roast-text.pop { animation: roastPop 0.35s ease; }
@keyframes roastPop {
  0% { opacity: 0; transform: translateY(6px) scale(0.98); }
  100% { opacity: 1; transform: none; }
}
.roast-note { margin-top: 0.6rem; font-size: 0.72rem; color: var(--text-dim); }

/* ---------------- Radar ---------------- */

.radar-card { display: flex; flex-direction: column; }

.radar-status {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.78rem;
  letter-spacing: 1.5px;
  color: var(--text-dim);
  font-family: 'Courier New', monospace;
  font-weight: 700;
}
.status-dot {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--text-dim);
}
.status-dot.live {
  background: var(--radar-accent);
  box-shadow: 0 0 8px var(--radar-accent);
  animation: blink 1.2s ease-in-out infinite;
}
@keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

.radar-wrap {
  position: relative;
  display: flex;
  justify-content: center;
  padding: 0.4rem 0;
}
#radarCanvas {
  display: block;
  max-width: 100%;
  /* A map has corners. The circle belonged to the scope, and the
     scope is now an option rather than the only thing on offer. */
  border-radius: 14px;
  touch-action: pan-y;
}
[data-radar="scope"] #radarCanvas { border-radius: 50%; }
[data-radar="map"] .radar-wrap { display: block; padding: 0; }
[data-radar="map"] .radar-legend { margin-top: 0.7rem; }
.radar-location {
  position: absolute;
  bottom: 0.8rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--input-bg);
  border: 1px solid var(--card-border);
  color: var(--text-dim);
  font-size: 0.72rem;
  border-radius: 999px;
  padding: 0.15rem 0.7rem;
  max-width: 90%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.radar-timeline {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 0.6rem 0;
}
.timeline-caption { font-size: 0.7rem; color: var(--text-dim); white-space: nowrap; }
.timeline-label {
  font-family: 'Courier New', monospace;
  font-weight: 700;
  font-size: 0.8rem;
  color: var(--accent);
  min-width: 4.2em;
  text-align: right;
}

input[type="range"] {
  flex: 1;
  -webkit-appearance: none;
  appearance: none;
  height: 6px;
  border-radius: 999px;
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  outline: none;
  min-width: 0;
}
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: var(--glow);
  cursor: grab;
}
input[type="range"]::-moz-range-thumb {
  width: 20px; height: 20px;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: var(--glow);
  cursor: grab;
}

/* Transport controls, sized to what they say.

   Every button stretched to at least 96px and grew to fill the row,
   so adding the two step buttons turned a tidy strip into a grid of
   eight slabs. The stepping buttons are icons and should stay
   icon-sized; the rest take the width of their own label. */
.radar-controls {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  align-items: center;
}
.radar-controls .btn { flex: 0 0 auto; min-width: 0; }
.radar-controls .btn-small { padding: 0.35rem 0.5rem; }
#radarStepBack, #radarStepFwd { min-width: 40px; justify-content: center; }

/* ---------------- Offline banner ---------------- */

.offline-banner {
  grid-area: alerts;
  background: var(--card);
  border: 1px solid var(--btn-border);
  border-radius: 12px;
  padding: 0.55rem 0.9rem;
  font-size: 0.85rem;
  color: var(--text-dim);
  text-align: center;
}

/* ---------------- Detail stats ---------------- */

.wx-detail {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(96px, 1fr));
  gap: 0.45rem;
  margin-top: 0.6rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--card-border);
}
.detail { display: flex; flex-direction: column; gap: 0.1rem; }
.detail-label {
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.7px;
  color: var(--text-dim);
}
.detail-value { font-weight: 700; font-size: 0.92rem; }

/* ---------------- Hourly ---------------- */

.hourly-wrap { width: 100%; overflow: hidden; }
#hourlyCanvas { display: block; width: 100%; touch-action: pan-y; cursor: crosshair; }
.hourly-legend {
  font-size: 0.7rem; color: var(--text-dim);
  display: inline-flex; align-items: center; gap: 0.35rem;
}
.legend-line {
  display: inline-block; width: 16px; height: 2px;
  background: var(--accent); border-radius: 2px;
}
.legend-bar {
  display: inline-block; width: 8px; height: 12px;
  background: var(--accent-2); opacity: 0.45; border-radius: 2px; margin-left: 0.35rem;
}

/* ---------------- Actionable stat + temperature modal ---------------- */

.stat-action { cursor: pointer; transition: border-color 0.15s ease, box-shadow 0.15s ease; }
.stat-action:hover { border-color: var(--accent); box-shadow: var(--glow); }
.stat-action:active { transform: scale(0.98); }
.stat-action:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.stat-hint { opacity: 0.75; font-size: 0.8em; }

body.modal-open { overflow: hidden; }

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(2px);
  z-index: 130;
}

.temp-modal {
  position: fixed;
  z-index: 140;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(760px, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 16px;
  box-shadow: var(--shadow), var(--glow);
  padding: 1.1rem 1.2rem calc(1.1rem + env(safe-area-inset-bottom));
}
.temp-modal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.7rem;
}
.temp-modal-head h2 { font-size: 1.05rem; letter-spacing: 0.4px; }
.temp-modal-summary { font-size: 0.8rem; color: var(--text-dim); margin-top: 0.15rem; }
.temp-chart-wrap { width: 100%; overflow: hidden; }
#tempChartCanvas { display: block; width: 100%; }
.temp-modal-note { font-size: 0.72rem; color: var(--text-dim); margin-top: 0.6rem; }

/* ---------------- Account ---------------- */

.account-signed-in {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  background: var(--input-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 0.5rem 0.6rem;
}
.account-avatar {
  width: 36px; height: 36px;
  border-radius: 50%;
  border: 1px solid var(--accent);
  flex: 0 0 auto;
  object-fit: cover;
}
.account-meta { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.account-name { font-weight: 700; font-size: 0.9rem; }
.account-email {
  font-size: 0.72rem;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* ---------------- Sign-in screen ---------------- */

.signin-modal {
  position: fixed;
  z-index: 140;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(420px, calc(100vw - 2rem));
  max-height: calc(100dvh - 2rem);
  overflow-y: auto;
  text-align: center;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 18px;
  box-shadow: var(--shadow), var(--glow);
  padding: 1.6rem 1.4rem 1.2rem;
}
.signin-close {
  position: absolute;
  top: 0.6rem;
  right: 0.6rem;
  min-height: 32px;
  padding: 0.2rem 0.55rem;
}
.signin-logo { display: block; margin: 0 auto 0.6rem; }
.signin-modal h2 {
  font-size: 1.15rem;
  letter-spacing: 0.3px;
  margin-bottom: 0.35rem;
}
.signin-sub {
  font-size: 0.82rem;
  color: var(--text-dim);
  line-height: 1.5;
  margin: 0 auto 1.1rem;
  max-width: 30ch;
}
.signin-modal .signin-buttons { align-items: center; }
.signin-modal .auth-note { margin-top: 0.4rem; }
.signin-fine {
  font-size: 0.72rem;
  color: var(--text-dim);
  line-height: 1.5;
  margin-top: 0.5rem;
}
.btn-plain {
  background: transparent;
  border-color: transparent;
  color: var(--text-dim);
  margin-top: 0.9rem;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.btn-plain:hover { color: var(--accent); }

/* Today against yesterday, under the condition line. */
.wx-yesterday {
  font-size: 0.78rem;
  color: var(--text-dim);
  margin-top: 0.25rem;
}

/* What the radar colours mean, in the only terms that hold for every
   source: order. */
.radar-legend {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.6rem 0 0.2rem;
  font-size: 0.68rem;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.6px;
}
.legend-bar {
  flex: 1;
  height: 8px;
  border-radius: 999px;
  border: 1px solid var(--card-border);
  background: linear-gradient(90deg,
    #3b82f6 0%, #22c55e 32%, #eab308 58%, #f97316 78%, #ef4444 100%);
}
.legend-label { flex: 0 0 auto; }

/* The legend names its bands rather than only its ends. "Light …
   Heavy" says the bar goes up; naming the middle says what the green
   you are looking at actually is. */
.radar-legend { display: block; }
.radar-legend .legend-bar { display: block; width: 100%; height: 9px; }
.legend-stops {
  display: flex;
  justify-content: space-between;
  margin-top: 0.28rem;
  font-size: 0.64rem;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-dim);
}
.legend-stops > span { flex: 1 1 0; text-align: center; }
.legend-stops > span:first-child { text-align: left; }
.legend-stops > span:last-child { text-align: right; }

/* The state of the radar is a dot. Only a source worth mentioning —
   a prediction, stale imagery, a simulation — gets words. */
.radar-status .status-dot { width: 9px; height: 9px; }
.radar-credit { display: block; opacity: 0.72; margin-top: 0.15rem; }

/* ---------------- Desktop-only settings ---------------- */

.desktop-panel { border: 1px solid var(--accent); border-radius: 14px; padding: 0.9rem; }
.setting-subhead {
  margin: 0 0 0.6rem;
  font-size: 0.95rem;
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}
.desktop-version { font-size: 0.75rem; color: var(--text-dim); font-weight: 400; }
.desktop-update {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  justify-content: space-between;
}
.desktop-update > div { flex: 1 1 12rem; min-width: 0; }
.update-bar {
  height: 5px;
  border-radius: 999px;
  background: var(--btn-bg);
  overflow: hidden;
  margin-top: 0.4rem;
}
.update-bar > span {
  display: block;
  height: 100%;
  width: var(--pct, 0%);
  background: var(--accent);
  transition: width 0.25s ease;
}

/* ---------------- Weather icons ---------------- */

.wx-svg { display: block; overflow: visible; }
.wx-glyph { display: inline-block; line-height: 1; }

/* The hero, laid out down the middle. */
.current-main {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 0.1rem;
  padding: 0.4rem 0 0.9rem;
}
.current-main .wx-icon { display: flex; justify-content: center; }
.current-main .wx-temp {
  font-size: clamp(3.4rem, 14vw, 5rem);
  font-weight: 300;
  letter-spacing: -2px;
  line-height: 1.05;
}
.current-main .wx-condition { font-size: 1rem; color: var(--text-dim); }
.wx-hilo-line {
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.5px;
  margin-top: 0.15rem;
}

/* The moving sky, directly under the hero.

   Full card width so it reads as the card's own horizon rather than a
   widget dropped in; masked at both ends so it fades into the card
   instead of stopping at a hard edge. Height is set by the script from
   the width, so it stays the same shape on a phone and a desktop. */
.wx-scene {
  width: 100%;
  margin-top: 0.85rem;
  border-radius: 14px;
  overflow: hidden;
  border: 1px solid var(--card-border);
  background: var(--btn-bg);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  pointer-events: none;
}
.wx-scene canvas { display: block; width: 100%; height: 72px; }

/* With the whole page already showing the sky, the strip's own border
   and fill read as a pale band stuck across the hero. Over a sky it
   keeps only its particles, which drift across the hero and belong
   there; with the background off it goes back to being a panel. */
[data-sky]:not([data-sky="none"]) .wx-scene {
  border: 0;
  background: none;
}


/* Accent swatches in Settings. */
.accent-preview { display: flex; gap: 0.4rem; margin-top: 0.5rem; }
.accent-dot {
  width: 22px; height: 22px;
  border-radius: 50%;
  border: 2px solid transparent;
}
.accent-dot.picked { border-color: var(--text); }

/* A day in detail. */
.day-roast {
  font-size: 0.9rem;
  line-height: 1.55;
  color: var(--text);
  background: var(--input-bg);
  border: 1px solid var(--card-border);
  border-left: 3px solid var(--accent);
  border-radius: 10px;
  padding: 0.6rem 0.7rem;
  margin-bottom: 0.9rem;
}

.day-modal { width: min(680px, calc(100vw - 2rem)); }
.day-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
  gap: 0.5rem;
  margin-bottom: 0.9rem;
}
.day-fact {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
  background: var(--input-bg);
  border: 1px solid var(--card-border);
  border-radius: 10px;
  padding: 0.45rem 0.55rem;
}
.day-fact-label {
  font-size: 0.66rem;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.6px;
}
.day-fact-value { font-size: 0.95rem; font-weight: 700; }

.day-hours-wrap {
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 0.3rem;
}
.day-hours {
  display: flex;
  align-items: flex-end;
  gap: 0.35rem;
  min-width: min-content;
}
.day-hour {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.2rem;
  flex: 0 0 auto;
  width: 46px;
}
.day-hour-temp { font-size: 0.72rem; font-weight: 700; }
.day-hour-bar {
  width: 10px;
  border-radius: 999px;
  background: linear-gradient(180deg, var(--accent), var(--accent-2, var(--accent)));
  opacity: 0.85;
}
.day-hour-rain { font-size: 0.64rem; color: var(--text-dim); }
.day-hour-rain.wet { color: var(--accent); font-weight: 700; }
.day-hour-time {
  font-size: 0.62rem;
  color: var(--text-dim);
  white-space: nowrap;
}

/* Pick a picture: emoji, so there is nothing to host or fetch. */
.avatar-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.6rem;
}
.avatar-choice {
  width: 36px;
  height: 36px;
  font-size: 1.05rem;
  line-height: 1;
  border-radius: 10px;
  border: 1px solid var(--card-border);
  background: var(--input-bg);
  color: inherit;
  cursor: pointer;
}
.avatar-choice:hover { border-color: var(--accent); }
.avatar-choice.picked {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent) inset;
}

/* Moving an account between devices. */
.transfer-code {
  width: 100%;
  margin-top: 0.5rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.68rem;
  line-height: 1.4;
  word-break: break-all;
  background: var(--input-bg);
  color: var(--text);
  border: 1px solid var(--card-border);
  border-radius: 10px;
  padding: 0.5rem;
  resize: vertical;
}
.transfer-restore { display: flex; gap: 0.5rem; margin-top: 0.6rem; }
.transfer-restore input { flex: 1; min-width: 0; font-size: 0.82rem; }

/* Sign-in setup rows in Settings. */
.provider-row { margin-top: 0.7rem; }
.provider-row label {
  display: block;
  font-size: 0.76rem;
  color: var(--text-dim);
  margin-bottom: 0.3rem;
}
.provider-row .setting-row { display: flex; gap: 0.5rem; }
.provider-row input { flex: 1; min-width: 0; font-size: 0.82rem; }
#authSetupStatus { margin-top: 0.7rem; }

/* Apple's mark is monochrome and takes the button's own colour. */
.apple-btn {
  background: #000;
  border: 1px solid #3a3a3a;
  color: #fff;
}
.apple-btn:hover { background: #141414; }
.apple-btn:disabled { opacity: 0.6; cursor: default; }
.apple-logo { display: inline-flex; flex: 0 0 auto; margin-top: -2px; }

/* A name on this device: always available, so it always has a place. */
.signin-or {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin: 1rem 0 0.9rem;
  color: var(--text-dim);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.8px;
}
.signin-or::before,
.signin-or::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--card-border);
}
.signin-local { text-align: left; }
.signin-local label {
  display: block;
  font-size: 0.78rem;
  font-weight: 700;
  margin-bottom: 0.35rem;
}
.signin-local .setting-row { display: flex; gap: 0.5rem; }
.signin-local input { flex: 1; min-width: 0; }
.signin-local-note {
  font-size: 0.72rem;
  color: var(--text-dim);
  line-height: 1.5;
  margin-top: 0.4rem;
}

/* The far end of the radar timeline: the present, or the forecast edge. */
.timeline-end.is-forecast {
  color: var(--accent);
  font-weight: 700;
}

/* The header button doubles as the avatar once somebody is signed in. */
.account-btn-avatar {
  width: 20px; height: 20px;
  border-radius: 50%;
  object-fit: cover;
  border: 1px solid var(--accent);
}

/* Sign-in. Google renders its own branded button; the Microsoft one is
   ours, following their mark: four squares, never recoloured. */
.account-lead {
  font-size: 0.85rem;
  color: var(--text);
  margin-bottom: 0.6rem;
}
.signin-buttons {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.5rem;
}
.signin-buttons:empty { display: none; }

.signin-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  width: 100%;
  max-width: 260px;
  min-height: 40px;
  border-radius: 999px;
  font-size: 0.9rem;
  font-weight: 600;
}
.ms-btn {
  background: #2f2f2f;
  border: 1px solid #3c3c3c;
  color: #fff;
}
.ms-btn:hover { background: #3a3a3a; }
.ms-btn:disabled { opacity: 0.6; cursor: default; }
.ms-logo { display: inline-flex; flex: 0 0 auto; }

/* Microsoft supplies no picture, so an initial stands in for one. */
.account-initial {
  width: 36px; height: 36px;
  flex: 0 0 auto;
  border-radius: 50%;
  border: 1px solid var(--accent);
  color: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 1rem;
}

.auth-note {
  font-size: 0.78rem;
  color: var(--text-dim);
  line-height: 1.5;
}
.auth-note code {
  background: var(--input-bg);
  border: 1px solid var(--card-border);
  border-radius: 5px;
  padding: 0 0.25rem;
  font-size: 0.92em;
}

.brand-avatar {
  width: 20px; height: 20px;
  border-radius: 50%;
  vertical-align: -4px;
  border: 1px solid var(--accent);
  margin-right: 0.15rem;
}

/* ---------------- Downloads ---------------- */

.download-modal {
  position: fixed;
  z-index: 140;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: min(560px, calc(100vw - 2rem));
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 16px;
  box-shadow: var(--shadow), var(--glow);
  padding: 1.1rem 1.2rem calc(1.1rem + env(safe-area-inset-bottom));
}

.dl-meta { font-size: 0.78rem; color: var(--text-dim); margin-bottom: 0.7rem; }

.dl-group {
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 0.6rem 0.75rem;
  margin-bottom: 0.6rem;
  background: var(--input-bg);
}
/* The visitor's own platform is called out first. */
.dl-mine { border-color: var(--accent); box-shadow: var(--glow); }

.dl-group-head {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 0.45rem;
}
.dl-icon { font-size: 1.15rem; }
.dl-platform { font-weight: 800; font-size: 0.95rem; }
.dl-badge {
  margin-left: auto;
  font-size: 0.64rem;
  text-transform: uppercase;
  letter-spacing: 0.7px;
  color: var(--accent);
  border: 1px solid var(--accent);
  border-radius: 999px;
  padding: 0.05rem 0.5rem;
}

.dl-asset {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--text);
  border: 1px solid var(--btn-border);
  background: var(--btn-bg);
  border-radius: 10px;
  padding: 0.5rem 0.75rem;
  margin-top: 0.35rem;
  font-size: 0.88rem;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.dl-asset:hover { background: var(--btn-hover); border-color: var(--accent); }
.dl-kind { font-weight: 600; }
.dl-size { color: var(--text-dim); font-size: 0.78rem; white-space: nowrap; }

.dl-all {
  display: inline-block;
  margin-top: 0.3rem;
  font-size: 0.82rem;
}
.dl-note {
  font-size: 0.75rem;
  color: var(--text-dim);
  margin-top: 0.7rem;
  line-height: 1.5;
}

/* ---------------- Rain nowcast ---------------- */

.nowcast-panel {
  margin-top: 0.8rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--card-border);
  border-radius: 12px;
  background: var(--input-bg);
}
.nowcast-head { display: flex; align-items: center; gap: 0.5rem; }
.nowcast-icon { font-size: 1.1rem; }
.nowcast-text { font-size: 0.92rem; font-weight: 600; }
.nowcast-strip-wrap { margin-top: 0.35rem; }
#nowcastStrip { display: block; width: 100%; }
.nowcast-precision {
  font-size: 0.64rem;
  color: var(--text-dim);
  text-transform: uppercase;
  letter-spacing: 0.6px;
  margin-top: 0.15rem;
}

/* ---------------- Air & sky ---------------- */

.aqi-row { display: flex; align-items: center; gap: 0.9rem; margin-bottom: 0.9rem; }
.aqi-badge {
  flex: 0 0 auto;
  min-width: 64px;
  height: 64px;
  border-radius: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  font-weight: 800;
  color: #08131c;
  border: 2px solid transparent;
}
.aqi-none      { background: var(--input-bg); color: var(--text-dim); border-color: var(--card-border); }
.aqi-good      { background: #3ec46d; }
.aqi-moderate  { background: #f2d047; }
.aqi-sensitive { background: #f5a35c; }
.aqi-unhealthy { background: #ef6a6a; color: #2a0709; }
.aqi-very      { background: #b57bdc; color: #1a0722; }
.aqi-hazardous { background: #a4557a; color: #fff; }
.aqi-label { font-weight: 800; font-size: 0.98rem; }
.aqi-advice { font-size: 0.8rem; color: var(--text-dim); margin-top: 0.1rem; }

.air-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
  gap: 0.5rem;
}
.sky-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 0.6rem;
  align-items: center;
  margin-top: 0.8rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--card-border);
}
.moon-block { display: flex; align-items: center; gap: 0.5rem; }
.moon-icon { font-size: 1.7rem; }
.moon-meta { display: flex; flex-direction: column; line-height: 1.2; }
.moon-meta small { color: var(--text-dim); font-size: 0.72rem; }

/* ---------------- Compare locations ---------------- */

.compare-empty, .compare-loading { color: var(--text-dim); font-size: 0.88rem; }
.compare-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 0.6rem;
}
.compare-tile {
  min-width: 0;
  overflow: hidden;
  font: inherit;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  background: var(--input-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  padding: 0.6rem 0.7rem;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}
.compare-tile:hover {
  transform: translateY(-3px);
  box-shadow: var(--glow);
  border-color: var(--accent);
}
.compare-tile:active { transform: scale(0.98); }
.compare-name {
  font-size: 0.76rem;
  font-weight: 700;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.compare-main { display: flex; align-items: center; gap: 0.4rem; margin: 0.15rem 0; }
.compare-icon { font-size: 1.5rem; }
.compare-temp { font-size: 1.5rem; font-weight: 800; }
.compare-cond { font-size: 0.76rem; color: var(--text-dim); }
.compare-stats {
  display: flex;
  justify-content: space-between;
  gap: 0.4rem;
  font-size: 0.72rem;
  margin-top: 0.3rem;
  color: var(--text-dim);
}
.compare-failed { opacity: 0.6; }

/* ---------------- Alerts ---------------- */

.alerts-panel {
  grid-area: alerts;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.alert-item {
  border-radius: 12px;
  padding: 0.6rem 0.9rem;
  border: 1px solid;
  background: var(--card);
  box-shadow: var(--shadow);
}
.alert-title { font-weight: 800; font-size: 0.92rem; }
.alert-body { font-size: 0.82rem; color: var(--text-dim); margin-top: 0.15rem; }
.alert-severe {
  border-color: var(--danger);
  background: linear-gradient(90deg, color-mix(in srgb, var(--danger) 18%, transparent), var(--card));
}
.alert-severe .alert-title { color: var(--danger); }
.alert-moderate { border-color: #f5a623; }
.alert-moderate .alert-title { color: #f5a623; }
.alert-minor { border-color: var(--btn-border); }

/* Radar zoom row + attribution */

.radar-zoom-row { margin-top: 0.5rem; align-items: center; }
.radar-zoom-row .btn { flex: 0 0 auto; min-width: 44px; }
.radar-range {
  font-family: 'Courier New', monospace;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--accent);
  min-width: 5em;
  text-align: center;
}
.radar-attribution {
  margin-top: 0.5rem;
  font-size: 0.66rem;
  color: var(--text-dim);
  text-align: center;
}
#radarCanvas { cursor: zoom-in; }
#radarCanvas:active { cursor: grabbing; }
.radar-card.fullscreen #radarCanvas { cursor: zoom-out; }
#radarCanvas:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }

/* ---------------- Fullscreen radar ---------------- */

/* Whatever the map's height works out to, everything in the card has
   to stay reachable. A fullscreen card that cannot scroll puts its
   own exit button off the top of the screen the moment the controls
   grow — which is exactly what happened. */
.radar-card.fullscreen {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.radar-fs-btn { margin-left: 0.35rem; }

/* Lock the page behind the expanded scope. */
body.radar-fullscreen { overflow: hidden; }

/* The overlay works everywhere, including iOS Safari, which will not
   grant the Fullscreen API to a non-video element. Where the real API
   is available it is used as well, and this styling still applies. */
.radar-card.fullscreen {
  position: fixed;
  inset: 0;
  /* iOS Safari overlays its toolbars on top of inset:0; dvh tracks the
     visible viewport instead. */
  height: 100vh;
  height: 100dvh;
  z-index: 120;
  margin: 0;
  border: none;
  border-radius: 0;
  max-width: none;
  background: radial-gradient(900px 600px at 50% 0%, var(--bg-2), var(--bg));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.9rem 0.9rem calc(0.9rem + env(safe-area-inset-bottom));
  overflow-y: auto;
}
.radar-card.fullscreen .card-head {
  width: 100%;
  max-width: 900px;
  margin-bottom: 0.2rem;
}
.radar-card.fullscreen .radar-timeline,
.radar-card.fullscreen .radar-controls,
.radar-card.fullscreen .radar-attribution {
  width: 100%;
  max-width: 900px;
}
.radar-card.fullscreen .radar-wrap { padding: 0; }

/* Native fullscreen paints its own backdrop black by default. */
.radar-card:fullscreen,
.radar-card:-webkit-full-screen {
  background: radial-gradient(900px 600px at 50% 0%, var(--bg-2), var(--bg));
}

/* Radar source badge */
.radar-source {
  font-size: 0.62rem;
  letter-spacing: 1px;
  border: 1px solid var(--btn-border);
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
  color: var(--text-dim);
}
.radar-source.live-source {
  color: var(--accent);
  border-color: var(--accent);
  box-shadow: var(--glow);
}

/* ---------------- Forecast ---------------- */

/* The forecast reads down the page: one row per day, with the day's
   range drawn against the whole week's so the rows compare. */
.forecast-row { display: flex; flex-direction: column; gap: 0.1rem; }
.forecast-card {
  display: grid;
  grid-template-columns: minmax(2.8rem, 3.4rem) 2.2rem minmax(2.2rem, 2.8rem)
                         minmax(2.4rem, 3rem) minmax(0, 1fr) minmax(2.4rem, 3rem);
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  min-width: 0;
  font: inherit;
  color: var(--text);
  cursor: pointer;
  text-align: left;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--card-border);
  border-radius: 0;
  padding: 0.5rem 0.25rem;
  transition: background 0.15s ease;
}
.forecast-card:last-child { border-bottom: 0; }
.forecast-card:hover { background: var(--input-bg); }
.forecast-card:active { background: var(--input-bg); }
.fc-day { font-size: 0.86rem; font-weight: 700; }
.fc-icon { display: flex; justify-content: center; align-items: center; }
.fc-icon .wx-glyph { font-size: 1.3rem; }
.fc-rain { font-size: 0.72rem; color: var(--accent); text-align: center; }
.fc-lo { color: var(--text-dim); font-size: 0.88rem; text-align: right; }
.fc-hi { font-weight: 800; font-size: 0.88rem; text-align: right; }
.fc-range {
  position: relative;
  height: 5px;
  min-width: 0;
  border-radius: 999px;
  background: var(--input-bg);
  border: 1px solid var(--card-border);
}
.fc-range-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent-2, var(--accent)), var(--accent));
}

/* ---------------- Favorites ---------------- */

.favorites-empty { color: var(--text-dim); font-size: 0.9rem; }
.favorites-list {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}
.fav-item {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--btn-border);
  border-radius: 10px;
  overflow: hidden;
  background: var(--btn-bg);
}
.fav-load {
  background: transparent;
  border: none;
  color: var(--text);
  padding: 0.5rem 0.85rem;
  min-height: 42px;
}
.fav-load:hover { background: var(--btn-hover); }
.fav-remove {
  background: transparent;
  border: none;
  border-left: 1px solid var(--btn-border);
  color: var(--text-dim);
  padding: 0 0.7rem;
}
.fav-remove:hover { color: var(--danger); background: var(--btn-hover); }

/* ---------------- Settings panel ---------------- */

.settings-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: 60;
  backdrop-filter: blur(2px);
}

.settings-panel {
  position: fixed;
  top: 0;
  right: 0;
  height: 100%;
  width: min(360px, 92vw);
  background: var(--card);
  border-left: 1px solid var(--card-border);
  box-shadow: var(--shadow);
  z-index: 70;
  padding: 1.2rem;
  transform: translateX(105%);
  transition: transform 0.28s ease;
  overflow-y: auto;
}
.settings-panel.open { transform: translateX(0); }

.settings-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.2rem;
}

.setting-group { margin-bottom: 1.3rem; }
.setting-group > label { display: block; font-weight: 700; margin-bottom: 0.4rem; font-size: 0.9rem; }
.setting-row { display: flex; gap: 0.5rem; }
.setting-hint { font-size: 0.75rem; color: var(--text-dim); margin-top: 0.35rem; }

.setting-group input[type="text"],
.setting-group input[type="password"],
.setting-group select {
  width: 100%;
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: 10px;
  padding: 0.55rem 0.8rem;
  min-height: 42px;
  outline: none;
}
.setting-row input[type="text"] { flex: 1; width: auto; min-width: 0; }
.setting-group input:focus, .setting-group select:focus { border-color: var(--accent); }

.toggle-row {
  display: flex !important;
  justify-content: space-between;
  align-items: center;
  cursor: pointer;
  font-weight: 700;
  font-size: 0.9rem;
}
.toggle-row input[type="checkbox"] {
  width: 44px; height: 24px;
  -webkit-appearance: none;
  appearance: none;
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: 999px;
  position: relative;
  transition: background 0.2s ease;
  cursor: pointer;
  flex-shrink: 0;
}
.toggle-row input[type="checkbox"]::after {
  content: '';
  position: absolute;
  top: 2px; left: 2px;
  width: 18px; height: 18px;
  border-radius: 50%;
  background: var(--text-dim);
  transition: transform 0.2s ease, background 0.2s ease;
}
.toggle-row input[type="checkbox"]:checked { background: var(--btn-hover); border-color: var(--accent); }
.toggle-row input[type="checkbox"]:checked::after { transform: translateX(20px); background: var(--accent); box-shadow: var(--glow); }

.version-readout {
  flex: 1;
  display: flex;
  align-items: center;
  font-family: 'Courier New', monospace;
  font-weight: 700;
  color: var(--accent);
  background: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: 10px;
  padding: 0 0.8rem;
  min-height: 42px;
}

.settings-footnote { font-size: 0.72rem; color: var(--text-dim); margin-top: 2rem; }

/* ---------------- Toast ---------------- */

.toast {
  position: fixed;
  left: 50%;
  bottom: 1.4rem;
  transform: translate(-50%, 20px);
  background: var(--card);
  border: 1px solid var(--accent);
  color: var(--text);
  border-radius: 12px;
  padding: 0.65rem 1.1rem;
  font-size: 0.9rem;
  box-shadow: var(--shadow), var(--glow);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.25s ease;
  z-index: 90;
  max-width: min(90vw, 480px);
  text-align: center;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast.error { border-color: var(--danger); }

/* ---------------- Footer ---------------- */

.app-footer {
  text-align: center;
  color: var(--text-dim);
  font-size: 0.75rem;
  padding: 1.2rem 1rem 2rem;
}

/* ---------------- Responsive ---------------- */

@media (max-width: 920px) {
  .app-main {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "alerts"
      "hero"
      "hourly"
      "forecast"
      "current"
      "radar"
      "air"
      "compare"
      "favorites";
    padding: 0.9rem;
    gap: 0.9rem;
  }
  .forecast-row {
    grid-template-columns: repeat(4, minmax(84px, 1fr));
    overflow-x: auto;
  }
}

@media (max-width: 640px) {
  .app-header { padding: 0.75rem 0.8rem; }
  .brand-logo { width: 42px; height: 42px; }
  .brand-text h1 { font-size: 1.1rem; }
  .header-tools { flex: 1 1 100%; max-width: none; }
  .tool-row { justify-content: stretch; }
  .tool-row .btn { flex: 1; }

  .wx-temp { font-size: 2.7rem; }
  .wx-icon { font-size: 3.2rem; }
  .current-main { gap: 0.8rem; }

  /* The forecast was a horizontal scroller until V19 and this block
     was the mobile half of it. The base rule is a vertical list now,
     and this one was still forcing every row to a fixed 96px — which
     is a flex-basis on the cross axis in a column, so each row was
     stretched to nearly twice the height of its contents. */

  /* Left to their own widths on a phone too: forcing half a row each
     is what produced four rows of two. */
  .radar-controls .btn { flex: 0 0 auto; min-width: 0; font-size: 0.85rem; }
}

/* Reduced motion: keep it calm */
@media (prefers-reduced-motion: reduce) {
  .welcome-logo { animation: none; }
  .status-dot.live { animation: none; }
  * { transition-duration: 0.01ms !important; }
}


/* ============================================================
   Aither Weather — Apple Weather inspired visual pass
   Soft iOS-style hierarchy, translucency, rounded cards and
   restrained accents. This is an original implementation, not a
   copy of Apple's proprietary UI.
   ============================================================ */

:root {
  --tile-radius: 20px;
  --tile-gap: 0.75rem;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
    system-ui, sans-serif;
  letter-spacing: -0.01em;
}

.card,
[data-cards="glass"] .card,
[data-cards="glass"] .tile {
  border: 1px solid rgba(255,255,255,.16);
  border-radius: 22px;
  box-shadow: 0 10px 30px rgba(0,0,0,.12);
  backdrop-filter: blur(24px) saturate(1.18);
  -webkit-backdrop-filter: blur(24px) saturate(1.18);
}

.card {
  padding: 1rem 1.05rem;
}

.card-head {
  margin-bottom: .65rem;
}

.card-head h2 {
  font-size: .95rem;
  font-weight: 650;
  letter-spacing: -.01em;
}

.current-main {
  display: grid;
  grid-template-columns: 1fr;
  justify-items: center;
  text-align: center;
  gap: .25rem;
  margin: .4rem 0 1rem;
}

.wx-icon {
  font-size: 4.5rem;
  filter: none;
  margin-bottom: .15rem;
}

.wx-temp {
  font-size: clamp(4.4rem, 18vw, 6rem);
  line-height: .9;
  font-weight: 200;
  letter-spacing: -0.065em;
  text-shadow: none;
}

.wx-condition {
  font-size: 1rem;
  font-weight: 500;
  margin-top: .4rem;
}

.wx-stats {
  gap: .5rem;
}

.stat {
  background: rgba(255,255,255,.08);
  border: 0;
  border-radius: 16px;
  padding: .65rem .75rem;
}

.stat-label {
  font-size: .67rem;
  letter-spacing: .35px;
  text-transform: none;
  opacity: .72;
}

.stat-value {
  font-size: .95rem;
  font-weight: 600;
}

.hourly-card canvas,
.forecast-card-panel canvas,
.sheet-chart-wrap canvas {
  border-radius: 16px;
}

[data-sky]:not([data-sky="none"]) .card {
  background: rgba(12,24,42,.30);
}

[data-theme="light"] [data-sky]:not([data-sky="none"]) .card,
[data-theme="light"] [data-sky]:not([data-sky="none"]) .tile {
  background: rgba(255,255,255,.46);
  border-color: rgba(255,255,255,.55);
}

[data-sky]:not([data-sky="none"]) .stat {
  background: rgba(255,255,255,.11);
}

@media (max-width: 600px) {
  .card {
    border-radius: 20px;
    padding: .9rem;
  }

  .wx-temp {
    font-size: 5rem;
  }

  .wx-icon {
    font-size: 4.2rem;
  }

  .tile-grid {
    gap: .55rem;
  }

  .tile {
    border-radius: 18px;
  }
}


/* ============================================================
   Aither Weather V29 — iOS Weather-inspired full UI pass
   ============================================================ */
:root{
  --tile-radius:18px;
  --tile-gap:.65rem;
}
html,body{overflow-x:hidden}
body{
  font-family:-apple-system,BlinkMacSystemFont,"SF Pro Text","SF Pro Display",system-ui,sans-serif;
  background:var(--bg);
}
.app-header{
  position:sticky;top:0;z-index:30;
  min-height:52px;
  padding-top:max(.35rem,env(safe-area-inset-top));
  background:rgba(20,55,95,.34)!important;
  border-bottom:1px solid rgba(255,255,255,.12)!important;
  backdrop-filter:blur(24px) saturate(1.35);
  -webkit-backdrop-filter:blur(24px) saturate(1.35);
}
.brand-logo{width:30px;height:30px;border-radius:9px}
.brand-text h1{font-size:1rem;font-weight:650;letter-spacing:-.02em}
.version-badge{font-size:.58rem}
.card{
  border:0!important;
  border-radius:20px!important;
  padding:1rem!important;
  box-shadow:0 8px 24px rgba(0,0,0,.10)!important;
  background:rgba(255,255,255,.105)!important;
  backdrop-filter:blur(28px) saturate(1.25);
  -webkit-backdrop-filter:blur(28px) saturate(1.25);
}
[data-theme="light"] .card{
  background:rgba(255,255,255,.50)!important;
  box-shadow:0 6px 20px rgba(30,60,90,.10)!important;
}
.card-head h2{
  font-size:.88rem;
  font-weight:600;
  letter-spacing:0;
}
.current-main{
  min-height:245px;
  justify-items:center;
  text-align:center;
  grid-template-columns:1fr;
  gap:.15rem;
  margin:.1rem 0 .7rem;
}
.wx-icon{font-size:4.7rem;filter:none;margin-top:.2rem}
.wx-temp{
  font-size:clamp(4.8rem,20vw,7rem);
  font-weight:200;
  letter-spacing:-.075em;
  line-height:.88;
  text-shadow:none;
}
.wx-condition{
  margin-top:.45rem;
  font-size:1.08rem;
  font-weight:500;
}
.wx-updated{font-size:.7rem;opacity:.72}
.wx-stats{grid-template-columns:repeat(3,1fr);gap:.45rem}
.stat{
  min-width:0;
  background:rgba(255,255,255,.09)!important;
  border:0!important;
  border-radius:15px;
  padding:.62rem .5rem;
}
.stat-label{font-size:.62rem;letter-spacing:0;text-transform:none}
.stat-value{font-size:.9rem;font-weight:600}
.tile-grid{gap:.55rem;margin-top:.65rem}
.tile{
  border:0!important;
  border-radius:18px!important;
  background:rgba(255,255,255,.08)!important;
  padding:.85rem!important;
  min-height:116px;
}
[data-theme="light"] .tile{background:rgba(255,255,255,.44)!important}
button,.btn,input,select{
  border-radius:14px;
}
.hourly-summary,.place-footer,.sheet-summary{font-size:.9rem}
@media(max-width:600px){
  .app-header{padding-left:max(.7rem,env(safe-area-inset-left));padding-right:max(.7rem,env(safe-area-inset-right))}
  .card{border-radius:20px!important}
  .current-main{min-height:235px}
  .wx-temp{font-size:5.6rem}
  .wx-icon{font-size:4.3rem}
  .wx-stats{grid-template-columns:repeat(3,1fr)}
}
