:root {
  --ink: #c8c2ba;
  --muted: #a89d94;
  --paper: #121110;
  --stage: #0c0b0a;
  --card: #1a1816;
  --line: #2e2a26;
  /* Palette: one meaning per colour (mirrored in app.js). */
  --accent: #e15a48;   /* orange: brand, selection, UV high, hot */
  --blue: #54c4ec;     /* sky: wind, rain, cool, UV low */
  --sea: var(--rain);   /* water (tide) shares the rain blue */
  --sun: var(--uva);
  --uva: #fcc41c;      /* yellow: UVA, moon, warm, UV moderate */
  --ice: #b9e2f2;      /* very cold */
  --cloud: #e4ecec;
  --uvb: #e4531b;
  --danger: #e07a70;
  --track: #3a342e;
  --hover: #241f1c;
  --selected: #332822;
  --faint: #7a726b;
  --rain: #3b86de;     /* deeper blue: rain only */
  --display: Barlow, Outfit, sans-serif;
  --title: Barlow, Outfit, sans-serif;
  color: var(--ink);
  background: var(--paper);
  font-family: Outfit, "Segoe UI", sans-serif;
  font-weight: 300;
  line-height: 1.45;
}

/* Text scales up on large screens: 16px up to ~1180px wide, ~20px on a
   1920px monitor. Nearly all sizes are in rem, so everything follows. */
html { font-size: clamp(16px, 0.55vw + 9.5px, 21px); }

* { box-sizing: border-box; }

body { margin: 0; }

button, input { font: inherit; }

button:focus-visible, input:focus-visible, .side-resize:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.app {
  --side: clamp(216px, 14vw, 290px);
  display: grid;
  /* --side-fit is set by fitSide() so place names stay on one line. */
  grid-template-columns: min(max(var(--side, 216px), var(--side-fit, 0px)), max(148px, 32vw)) minmax(0, 1fr);
  height: 100vh;
  height: 100dvh;
  background: var(--paper);
}

.side {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  padding: 28px 14px 20px 18px;
  background: transparent;
  border-right: 1px solid var(--line);
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-width: thin;
}

.side-resize {
  position: absolute;
  top: 0;
  right: 0;
  width: 8px;
  height: 100%;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: col-resize;
  touch-action: none;
  z-index: 2;
}

/* Brand block at the top of the sidebar: logo, name, tagline, flush left. */
.brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

/* Logo with "The / Elements" beside it over two lines, flush left. */
.brand-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: max-content; /* fitSide() measures it */
}

.brand-logo {
  flex: none;
  width: 3rem;
  height: 3rem;
}

.eyebrow.brand-name {
  font-size: 1rem;
  line-height: 1.2;
}

.brand .side-note { margin: 12px 0 0; }

/* "Places" starts its own section, styled like the "Add a place" label. */
h1.side-heading {
  margin: 52px 0 8px;
  color: var(--muted);
  font-family: inherit;
  font-size: 0.98rem;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.45;
  text-transform: none;
}

.eyebrow {
  margin: 0;
  color: var(--accent);
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

h1 {
  margin: 6px 0 0;
  font-family: var(--title);
  font-size: 1.7rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  line-height: 1;
  text-transform: uppercase;
}

.side-note {
  margin: 10px 0 22px;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 400;
}

#place-list {
  display: grid;
  gap: 2px;
  align-content: start;
}

.place-row {
  display: flex;
  align-items: stretch;
  gap: 0;
  min-width: 0;
  border-radius: 16px;
}

#place-list.reordering .place-row { transition: transform 140ms ease; }

.place-row.lifting {
  position: relative;
  z-index: 3;
  border-radius: 16px;
  background: #2c2420;
  transition: none;
}

.place-row:hover { background: var(--hover); }
.place-row.selected,
.place-row.selected:hover { background: var(--selected); }

.place {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  justify-content: flex-start;
  gap: 6px;
  align-items: baseline;
  border: 0;
  border-radius: 16px;
  padding: 10px 8px 10px 12px;
  background: transparent;
  color: inherit;
  text-align: left;
  cursor: pointer;
  user-select: none;
  -webkit-touch-callout: none;
}

.place-hold {
  position: absolute;
  left: 12px;
  top: 10px;
  color: var(--accent);
  font-size: 0.88rem;
  font-weight: 300;
  letter-spacing: 0;
  line-height: 1.25;
  text-transform: uppercase;
  pointer-events: none;
  opacity: 0;
}

.place.holding .place-name,
.place.holding .place-time,
.place.holding .place-temp {
  opacity: 0;
  transition: opacity 0.4s ease;
}

.place.holding .place-hold {
  opacity: 1;
  transition: opacity 0.4s ease;
}

.place-row:has(.place.holding) { background: #2c2420; }

.place-row.selected .place-hold { left: 26px; }

.place-name {
  flex: 0 1 auto;
  min-width: 0;
  font-weight: 300;
  font-size: 0.88rem;
  letter-spacing: 0;
  line-height: 1.25;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.place-row.selected .place-name::before {
  content: "";
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--accent);
  transform: translateY(-1px);
}

.place-time,
.place-temp {
  flex: none;
  font-weight: 300;
  font-variant-numeric: tabular-nums;
  font-size: 0.88rem;
  line-height: 1.25;
  color: var(--muted);
  white-space: nowrap;
}

.place-time { margin-left: auto; }

.place-temp { margin-left: 14px; }

.place-row.selected .place-time,
.place-row.selected .place-temp { color: var(--ink); }

.search {
  padding-top: 34px;
  display: grid;
  gap: 8px;
}

.search label {
  color: var(--muted);
  font-size: 0.98rem;
  font-weight: 400;
}

/* The town box, Search and Refresh share one size. */
input[type="search"] {
  width: 100%;
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 10px 14px;
  background: var(--card);
  color: var(--ink);
  font-size: 0.88rem;
  font-weight: 400;
}

input[type="search"]::placeholder { color: var(--faint); }

input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button {
  -webkit-appearance: none;
  appearance: none;
  display: none;
}

.search button[type="submit"], .retry {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 6px 12px;
  background: #2a2724;
  color: var(--ink);
  font-weight: 400;
  cursor: pointer;
}

.search button[type="submit"] { font-size: 0.88rem; padding: 8px 14px; }

.head-actions {
  display: flex;
  flex: none;
  margin-left: auto;
  gap: 8px;
  align-items: center;
}

.head-actions button {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 8px 14px;
  background: transparent;
  color: var(--muted);
  font-size: 0.88rem;
  font-weight: 400;
  cursor: pointer;
}

.results { display: grid; gap: 6px; }

.result {
  width: 100%;
  text-align: left;
  white-space: normal;
  overflow-wrap: break-word;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 8px 12px;
  background: var(--card);
  color: var(--ink);
  font-weight: 300;
  font-size: 0.88rem;
  letter-spacing: 0;
  text-transform: uppercase;
  cursor: pointer;
}

.hint { margin: 0; color: var(--muted); font-size: 0.88rem; font-weight: 400; }

.stage {
  min-width: 0;
  min-height: 0;
  overflow: auto;
  /* On very wide screens the content stops at 1440px and sits centred. */
  padding: 28px max(28px, calc((100% - 1440px) / 2)) 36px;
  background: var(--stage);
  container-type: inline-size;
  container-name: stage;
}

.stage-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: flex-start;
  margin-bottom: clamp(18px, 1.3vw, 28px);
}

.stage-head > div { min-width: 0; flex: 1; }

.stage-head > .head-actions { flex: none; }

h2 {
  margin: 0;
  font-family: var(--title);
  font-size: clamp(1.45rem, 2.6vw, 2.15rem);
  font-weight: 400;
  letter-spacing: 0.04em;
  line-height: 1;
  text-transform: uppercase;
}

/* Space under the city name grows with the screen: 9px on phones, ~15px at 1920px. */
.where { margin: clamp(9px, 0.8vw, 18px) 0 0; color: var(--muted); font-size: 0.92rem; font-weight: 400; }

.map-frame {
  position: relative;
  height: 16.25rem;
  border-radius: 22px;
  overflow: hidden;
  background: #141311;
  border: 1px solid var(--line);
  cursor: pointer;
}

.map-frame:hover { border-color: var(--muted); }

.map-frame canvas { width: 100%; height: 100%; display: block; pointer-events: none; }

.map-flow {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.map-pop {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  padding: 24px;
  background: rgb(8 7 6 / 74%);
}

.map-stage {
  display: flex;
  flex-direction: column;
  width: min(960px, 100%);
  height: min(720px, 100%);
  border: 1px solid var(--line);
  border-radius: 22px;
  overflow: hidden;
  background: #141311;
}

.map-tools {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 12px;
}

.map-name {
  margin: 0;
  font-family: var(--title);
  font-size: 1.15rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  line-height: 1;
  text-transform: uppercase;
}

.map-tools .where { margin: 4px 0 0; font-size: 0.82rem; }

.map-canvas-wrap {
  position: relative;
  flex: 1;
  min-height: 0;
}

.map-canvas-wrap canvas {
  width: 100%;
  height: 100%;
  display: block;
  cursor: grab;
  touch-action: none;
}

.map-zoom {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 2;
  display: grid;
  gap: 6px;
}

.map-zoom button,
.map-close {
  border: 1px solid var(--line);
  border-radius: 999px;
  background: #2a2724;
  color: var(--ink);
  font: inherit;
  font-weight: 400;
  cursor: pointer;
}

.map-zoom button {
  width: 36px;
  height: 36px;
  padding: 0;
  font-size: 1.2rem;
  line-height: 1;
}

.map-zoom button:disabled { opacity: 0.35; cursor: default; }

.map-close { padding: 6px 12px; }

.chart-unit {
  margin-left: 8px;
  color: var(--faint);
  font-family: var(--display);
  letter-spacing: 0;
  text-transform: none;
}

.map-credit {
  position: absolute;
  right: 8px;
  bottom: 5px;
  z-index: 2;
  font-size: 0.6rem;
  font-weight: 400;
  color: var(--ink);
  opacity: 0.55;
  text-shadow: 0 0 3px #000;
}

.map-credit:hover, .map-credit:focus-within { opacity: 1; }

.map-credit a { color: inherit; text-decoration: none; }

/* Sizes .light-times to the panel width; the dial panel itself can't be a
   container because that would stop it joining the .dials subgrid. */
.light-box { container-type: inline-size; }

.light-times {
  margin: 2px 0 0;
  font-family: var(--display);
  font-weight: 500;
  font-size: clamp(0.78rem, 5.5cqi, 1.45rem);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  line-height: 1.15;
  white-space: nowrap;
}

.light-times .uva { color: var(--uva); }
.light-times .uvb { color: var(--uvb); }
.light-times .missing { color: var(--muted); }
.light-times .dot { margin: 0 0.32em; color: var(--faint); }

.dials {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 10px;
  margin-top: 10px;
}

.panel {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 22px;
  padding: 14px 14px 12px;
  min-width: 0;
  container-type: inline-size;
}

/* Each dial spans four shared rows (title, reading, circle, footer), so the
   circles start at the same height in every panel across a row. */
.dial {
  container-type: normal;
  display: grid;
  grid-row: span 4;
  grid-template-rows: subgrid;
  row-gap: 0;
  align-items: start;
  margin-bottom: 10px;
  padding: 10px 8px 8px;
  text-align: center;
}

.panel h3, .block h3 {
  margin: 0 0 2px;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.dial h3 {
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
}

.dial-read { margin: 0; }

.dial-value {
  display: block;
  font-family: var(--display);
  font-weight: 500;
  font-size: 1.55rem;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.dial-unit {
  display: block;
  margin-top: 2px;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 400;
  line-height: 1.2;
}

.gauge, .compass, .moon-disc, .spark {
  width: min(100%, 148px);
  height: auto;
  margin: 2px auto 0;
  display: block;
}

.spark { margin-top: 0; }

/* Breathing room between the circles and the text above and below them. */
.dial .gauge, .dial .compass { margin-top: 10px; }
/* Captions keep clear of the card's sides: more room as cards get wider. */
.dial-foot { padding: 5px clamp(8px, 8%, 30px) 0; }

.caption {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 400;
  line-height: 1.3;
}

.caption.sun-edge { margin: 0 0 2px; }
.caption.light-note { color: var(--faint); text-wrap: balance; }

.chart-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 10px;
  align-items: stretch;
}

.chart-row .block { margin-top: 0; }

.block { margin-top: 10px; }

/* Tide and moon row, under the temperature and rain charts. */
.sea-row {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
  gap: 10px;
  margin-top: 10px;
}

.sea-row.solo { grid-template-columns: minmax(0, 1fr); }
.sea-row .block { margin-top: 0; }

.tide-chart {
  position: relative;
  height: 7.5rem;
  margin-top: 8px;
}

.tide-chart svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.tide-fill { fill: var(--sea); opacity: 0.12; }

.tide-line {
  fill: none;
  stroke: var(--sea);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

.tide-mark { position: absolute; width: 0; height: 0; }

.tide-dot, .tide-now {
  position: absolute;
  border-radius: 50%;
  transform: translate(-50%, -50%);
}

.tide-dot { width: 7px; height: 7px; background: var(--sea); }

/* Standard "now" marker: 10px across, cream centre, 2px orange ring. */
.tide-now {
  width: 6px;
  height: 6px;
  background: #f4efe9;
  box-shadow: 0 0 0 2px var(--accent);
}

.tide-label {
  position: absolute;
  left: 0;
  display: grid;
  justify-items: center;
  transform: translateX(-50%);
  font-family: var(--display);
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  white-space: nowrap;
}

.tide-mark.high .tide-label { bottom: 7px; }
.tide-mark.low .tide-label { top: 7px; }
.tide-mark.edge-left .tide-label { transform: none; justify-items: start; }
.tide-mark.edge-right .tide-label { transform: translateX(-100%); justify-items: end; }

.tide-time { color: var(--ink); font-size: 0.78rem; font-weight: 500; }
.tide-height { color: var(--faint); font-size: 0.68rem; }

.tide-axis {
  position: relative;
  height: 1.1rem;
  margin-top: 4px;
  color: var(--faint);
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
}

.tide-axis span { position: absolute; transform: translateX(-50%); }
/* Same breathing room under every chart before its caption. */
.tide .caption, .chart-row .caption { margin-top: 16px; }
.tide-axis span:first-child { transform: none; }
.tide-axis span:last-child { transform: translateX(-100%); }

/* The moon and its text fill the card below the title, centred vertically
   however tall the card is (it matches the tide card's height). */
.moon { display: flex; flex-direction: column; }

.moon-body {
  flex: 1;
  align-content: center;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 20px 18px;
  /* A little into the card's side padding, so the moon reaches full dial size
     even in the narrow column beside the tide card. */
  margin: 16px -6px 8px;
}

.moon-disc { flex: none; margin: 0; }

/* Text beside the moon: the space below matches what sits above it (the
   title, one line of 0.78rem text plus its 2px margin, and the 16px gap).
   When the text has dropped below the moon (.stacked) it isn't needed. */
.moon:not(.stacked) .moon-body { margin-bottom: calc(16px + 0.78rem * 1.45 + 2px); }

/* On phones the full match looks too roomy; a little extra is enough. */
@media (max-width: 700px) {
  .moon:not(.stacked) .moon-body { margin-bottom: 18px; }
}

/* Beside a taller moon card, the tide chart grows to fill its card. */
.sea-row .tide { display: flex; flex-direction: column; }
.sea-row .tide .tide-chart { flex: 1 0 auto; min-height: 7.5rem; }
.moon-dark { fill: #2b2724; stroke: #4a433c; stroke-width: 1.5; }
.moon-lit-part { fill: var(--uva); }

.moon-text { min-width: 8rem; }
.moon-text p { margin: 0; }

.moon-phase {
  color: var(--ink);
  font-size: 0.78rem;
  font-weight: 400;
  line-height: 1.3;
}

.moon-lit { color: var(--muted); }
.moon-text .nowrap { white-space: nowrap; }
.moon-text .caption { margin-top: 6px; }
.moon-text .moon-next { margin-top: 2px; color: var(--faint); }

@media (max-width: 700px) {
  .sea-row { grid-template-columns: minmax(0, 1fr); }
}

.fine {
  margin: 14px 0 0;
  color: var(--faint);
  font-size: 0.75rem;
  font-weight: 400;
}

.week {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
  margin-top: 8px;
}

.week-day {
  display: grid;
  justify-items: center;
  align-content: start;
  gap: 1px;
  min-width: 0;
  width: 100%;
  padding: 6px 0;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: inherit;
  font: inherit;
  cursor: pointer;
}

.week-day:hover { background: var(--hover); }

/* The picked day: an orange outline only, no fill. */
.week-day.picked,
.week-day.picked:hover {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--accent);
}

.week-day.today .week-k { color: var(--accent); }

.week-k, .week-lo, .week-rain {
  color: var(--muted);
  font-size: 0.68rem;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}

/* Day names match the panel titles (This week, Temperature, Wind…). */
.week-k { font-size: 0.78rem; }

.week-lo, .week-rain { font-family: var(--display); }

.week-sky { font-size: 0.95rem; line-height: 1.2; }
.week-sky svg { display: block; width: 1.45em; height: 1.45em; margin: 1px 0; }
.week-rain { color: var(--rain); }

/* Weather icon parts. */
.sky-sun { fill: var(--uva); }
.sky-ray { stroke: var(--uva); stroke-width: 1.6; stroke-linecap: round; }
.sky-cloud { fill: var(--cloud); }
.sky-cloud.grey { fill: #b7bfc4; }
.sky-cloud.dark { fill: #8d969c; }
.sky-drop { stroke: var(--rain); stroke-width: 1.8; stroke-linecap: round; }
.sky-snow { fill: var(--ice); }
.sky-bolt { fill: var(--uva); }
.sky-fog { stroke: #a9b0b5; stroke-width: 1.8; stroke-linecap: round; }
.sky-fog-dot { fill: var(--faint); }

.week-hi {
  font-family: var(--display);
  font-weight: 500;
  font-size: 0.95rem;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.week-rain:empty { min-height: 0.9em; }

.bars {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 64px;
}

.bars.labeled {
  height: auto;
  margin-top: 8px; /* same gap under the title as the This week days */
  align-items: stretch;
}

.bars.labeled .bar-col { height: auto; }

.bars.labeled .bar-track {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100%;
  height: 56px;
}

.temp-n {
  display: block;
  height: 13px;
  margin-bottom: 3px;
  color: var(--faint);
  font-family: var(--display);
  font-size: 0.62rem;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  line-height: 13px;
  text-align: center;
  white-space: nowrap;
}

.temp-n.now { color: var(--ink); }

.bar-col {
  flex: 1;
  min-width: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  gap: 4px;
}

.bar {
  width: 6px;
  min-height: 2px;
  border-radius: 99px;
  background: var(--rain);
}

.bar.temp.sun { background: var(--uva); }
.bar.temp.cloud { background: var(--cloud); }
.bar.temp.rain { background: var(--rain); }
.bar.quiet { opacity: 0.28; }

.bar-col .hour-tick {
  flex: none;
  width: 6px;
  height: 6px;
  margin: 2px 0;
  border-radius: 50%;
  background: transparent;
}

/* The current hour: the standard now marker under its bar. */
.bar-col .hour-tick.on { background: #f4efe9; box-shadow: 0 0 0 2px var(--accent); }

.bar-col .hour.now { color: var(--accent); }

.bar-col span {
  height: 14px;
  color: var(--muted);
  font-family: var(--display);
  font-size: 0.68rem;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}

.track {
  position: relative;
  height: 10px;
  border-radius: 99px;
  background: var(--track);
  overflow: hidden;
}

.band { position: absolute; top: 0; bottom: 0; }
.band.uva { background: var(--uva); }
.band.uvb { background: var(--uvb); }

.now-mark {
  position: absolute;
  top: -2px;
  bottom: -2px;
  width: 2px;
  border-radius: 99px;
  background: var(--ink);
}

.sun-times {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  margin-top: 10px;
}

.chip-k {
  display: block;
  color: var(--muted);
  font-size: 0.68rem;
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.chip-v {
  font-family: var(--display);
  font-weight: 500;
  font-size: 1.15rem;
  font-variant-numeric: tabular-nums;
}

@container (max-width: 460px) {
  .sun-times { grid-template-columns: 1fr 1fr; }
}

.muted { color: var(--muted); }
.error { color: var(--danger); }

@media (max-width: 860px) {
  .app { --side: 184px; }
  .side { padding: 16px 10px; }
  h1 { font-size: 1.15rem; }
  .brand-logo { width: 2.6rem; height: 2.6rem; }
  .brand-row { gap: 10px; }
  .eyebrow.brand-name { font-size: 0.9rem; }
  h1.side-heading { margin-top: 44px; }
  h2 { font-size: 1.25rem; }
  .place { padding: 8px 4px 8px 8px; gap: 4px; }
  .place-hold { left: 8px; top: 8px; font-size: 0.8rem; }
  .place-row.selected .place-hold { left: 22px; }
  .place-name, .place-time, .place-temp { font-size: 0.8rem; }
  .result { font-size: 0.8rem; }
  input[type="search"] { font-size: 0.88rem; padding: 9px 12px; }
  .stage { padding: 14px 10px 20px; }
  .dials { column-gap: 6px; }
  .dial { padding: 8px 4px 6px; margin-bottom: 6px; }
  .dial-value { font-size: 1.35rem; }
  .dial h3, .caption { font-size: 0.78rem; }
  .dial-unit { font-size: 0.72rem; }
  .gauge, .compass, .moon-disc { width: min(100%, 96px); }
  .map-frame { height: 240px; border-radius: 16px; }
  .panel { border-radius: 16px; }
  .week-hi { font-size: 0.8rem; }
  .week-lo, .week-rain { font-size: 0.6rem; }
  .week-sky { font-size: 0.8rem; }
  .week-day { padding: 4px 0; }
  .search { margin-top: 16px; }
  .chip-v { font-size: 1rem; }
}

@media (max-width: 700px) {
  .chart-row { grid-template-columns: 1fr; }
}

@media (max-width: 520px) {
  .app { --side: 160px; }
  .side { padding: 12px 8px; }
  .side-note { font-size: 0.62rem; }
  .stage { padding: 12px 8px 18px; }
  .panel { padding: 8px 6px; }
  .dials { column-gap: 4px; }
  .dial { margin-bottom: 4px; }
  .gauge, .compass, .moon-disc { width: min(100%, 8rem); }
  .dial-value { font-size: 1.2rem; }
  .week { gap: 0; }
  .map-frame { height: 240px; }
  .head-actions button { padding: 6px 10px; }
}

@container stage (min-width: 560px) {
  .dials {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    column-gap: 8px;
  }
  .dial { padding: 8px 4px 6px; margin-bottom: 0; }
  .dial-value { font-size: 1.35rem; }
  .dial h3, .caption { font-size: 0.78rem; }
  .dial-unit { font-size: 0.72rem; }
  .gauge, .compass, .moon-disc { width: min(100%, 7rem); }
  .light-times { font-size: clamp(0.88rem, 10cqi, 1.15rem); }
}

/* Places menu: below 700px the sidebar becomes a slide-in panel opened from
   the ☰ button in the page header, so the weather gets the full width. */
.menu-toggle, .side-scrim { display: none; }

@media (max-width: 700px) {
  .app { grid-template-columns: minmax(0, 1fr); }

  .app .side {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 20;
    width: min(84vw, 320px);
    padding: 20px 16px;
    background: var(--paper);
    transform: translateX(-100%);
    visibility: hidden;
    transition: transform 0.25s ease, visibility 0s linear 0.25s;
  }

  .app.menu-open .side {
    transform: none;
    visibility: visible;
    box-shadow: 8px 0 24px rgb(0 0 0 / 45%);
    transition: transform 0.25s ease;
  }

  .side-resize { display: none; }

  .side-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 19;
    background: rgb(0 0 0 / 55%);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s ease;
  }

  .app.menu-open .side-scrim { opacity: 1; pointer-events: auto; }

  .menu-toggle {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    margin: -4px 0 0 -4px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 50%;
    background: transparent;
    color: var(--ink);
    cursor: pointer;
  }

  .menu-toggle svg { width: 20px; height: 20px; }

  .app .side-note { font-size: 0.72rem; }

  .app .place-name {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    white-space: normal;
    overflow-wrap: break-word;
  }
}

@media (max-width: 700px) and (prefers-reduced-motion: reduce) {
  .app .side, .side-scrim { transition: none; }
}

/* Any card opened full screen. The sheet is a size container, so text and
   graphics scale with the enlarged view itself (cqmin = the smaller of its
   width and height), on phones and large screens alike. */
.dial-pop { padding: 8px; background: rgb(8 7 6 / 88%); }

.dial-sheet {
  display: flex;
  flex-direction: column;
  width: min(960px, 100%);
  height: min(820px, 100%);
  overflow-y: auto;
  border: 1px solid var(--line);
  border-radius: 22px;
  background: var(--card);
  container-type: size;
}

.dial-sheet .map-name { font-size: clamp(1.1rem, 3.2cqmin, 1.6rem); }
.dial-sheet .map-name .chart-unit { font-size: 0.75em; }
.dial-sheet .map-close { font-size: clamp(0.9rem, 2.4cqmin, 1.2rem); padding: 0.4em 1em; }

.dial-big {
  display: grid;
  grid-template-rows: auto;
  align-content: center;
  justify-items: stretch;
  text-align: center;
  gap: 4px;
  flex: 1;
  margin: 0;
  padding: 8px clamp(20px, 5cqw, 64px) 28px;
  border: 0;
  background: transparent;
}

.dial-big h3 { display: none; }

/* Dials */
.app ~ .dial-pop .dial-big .dial-value { font-size: clamp(3.2rem, 15cqmin, 8rem); }
.app ~ .dial-pop .dial-big .dial-unit { font-size: clamp(1.05rem, 4.2cqmin, 2rem); margin-top: 6px; }
.app ~ .dial-pop .dial-big .caption { font-size: clamp(1.05rem, 4.2cqmin, 2rem); }
.app ~ .dial-pop .dial-big .light-times { font-size: clamp(1.8rem, 8cqmin, 4rem); }

.dial-pop .dial-big .gauge,
.dial-pop .dial-big .compass,
.dial-pop .dial-big .moon-disc,
.dial-pop .dial-big .spark {
  width: min(80cqw, 48cqh, 520px);
  margin-top: 16px;
}

.dial-pop .dial-big .dial-foot { padding-top: 12px; }
.dial-pop .dial-big .light-note { max-width: 26rem; margin-inline: auto; }

/* Moon: moon above, text below, both enlarged. */
.dial-pop .moon-body { flex-direction: column; gap: 4cqmin; margin: 0; }
.dial-pop .moon-text { text-align: center; }
.app ~ .dial-pop .dial-big .moon-phase { font-size: clamp(1.2rem, 5cqmin, 2.4rem); }
.dial-pop .moon-text .caption { margin-top: 10px; }

/* Hourly charts and tide: taller bars and wave, larger numbers. */
.dial-pop .block.dial-big { text-align: left; }
.dial-pop .dial-big .bars.labeled { margin-top: 3cqh; gap: 0.6cqw; }
.dial-pop .dial-big .bars.labeled .bar-track { height: 42cqh; }
.dial-pop .dial-big .bar { width: clamp(6px, 1.5cqw, 16px); }
/* Fixed-height label rows (empty ones too), so every bar shares a baseline. */
.app ~ .dial-pop .dial-big .temp-n,
.app ~ .dial-pop .dial-big .bar-col .hour {
  height: 1.4em;
  font-size: clamp(0.72rem, 2.6cqmin, 1.25rem);
  line-height: 1.4em;
}
.dial-pop .dial-big .tide-chart { height: 46cqh; margin-top: 3cqh; }
.app ~ .dial-pop .dial-big .tide-time { font-size: clamp(0.85rem, 3cqmin, 1.5rem); }
.app ~ .dial-pop .dial-big .tide-height,
.app ~ .dial-pop .dial-big .tide-axis { font-size: clamp(0.72rem, 2.4cqmin, 1.2rem); }
.dial-pop .dial-big .tide-axis { height: auto; margin-top: 8px; padding-bottom: 1.4em; }
.dial-pop .block.dial-big > .caption { margin-top: 3cqh; }

/* Cards are clickable on every screen size. */
#day-detail .dial[role="button"],
.chart-row .block[role="button"],
.sea-row .panel[role="button"] { cursor: pointer; transition: border-color 0.15s ease; }

#day-detail .dial[role="button"]:hover,
.chart-row .block[role="button"]:hover,
.sea-row .panel[role="button"]:hover { border-color: #4a433c; }

#day-detail .dial[role="button"]:active,
.chart-row .block[role="button"]:active,
.sea-row .panel[role="button"]:active { background: var(--hover); }

/* Wind unit chips (km/h · m/s · mph) in the wind card's top-right corner. */
.wind-panel { position: relative; }

.unit-chips {
  position: absolute;
  top: 7px;
  right: 7px;
  display: flex;
  gap: 4px;
}

.wind-panel.compact .unit-chips { flex-direction: column; gap: 3px; }
.dial-pop .wind-panel.compact .unit-chips { flex-direction: row; }
.unit-chip[hidden] { display: none; }

.unit-chip {
  padding: 1px 6px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--faint);
  font: inherit;
  font-size: 0.6rem;
  font-weight: 400;
  line-height: 1.35;
  cursor: pointer;
}

.unit-chip:hover { color: var(--ink); }

/* In the full-screen card they sit in a row, large enough to tap easily. */
.dial-pop .unit-chips {
  top: 0;
  right: 16px;
  gap: 8px;
}

.dial-pop .unit-chip {
  padding: 5px 14px;
  font-size: 0.95rem;
}

/* Phones: the header (☰, place name, date and time, Refresh) stays fixed
   at the top while the page scrolls under it, with the two lines closer. */
@media (max-width: 700px) {
  .stage { padding-top: 0; }

  .stage-head {
    position: sticky;
    top: 0;
    z-index: 10;
    align-items: center;
    margin: 0 -10px 14px;
    padding: 12px 10px 10px;
    background: var(--stage);
    box-shadow: 0 1px 0 var(--line);
  }

  .where { margin-top: 3px; }
}

@media (max-width: 520px) {
  .stage-head { margin-inline: -8px; padding-inline: 8px; }
}

