/* The Weather pane: a stack of cards on the shared field, one per question the pane
   answers -- now, alerts, the next two hours, the next day, the week, the details -- with
   the radar slot the next slice fills already holding its place in the order. Everything
   here composes the shared primitives (.app-card, .app-row, .app-tag, .app-divider-list,
   .app-field, .app-quiet-button); the rules below only position them and size the few
   things that are genuinely this pane's own: the one big temperature, the two scrollable
   strips, and the two-column desktop read. The section itself is an .app-scroller-field,
   which is where the pane's gutters and its bottom clearance come from -- the same place
   Groceries' cards get theirs, so nothing is restated here. */

.weather-title:focus {
  outline: none;
}

/* On-wall lines between the toolbar and the card stack, matching the shared source line's
   zero-margin read inside the header's subtitle. */
#weather-updated {
  margin: 0;
}

#weather-status {
  margin: 0;
}

/* The toolbar carries the pane's live controls (the location select, Places, the units
   select, refresh), so it keeps the shared bar's shape -- but it sits inside the padded
   field like Meals' own bars, so it takes the "not a band" zeroing rather
   than drawing a second surface on the wallpaper. It wraps rather than clipping: the
   controls do not fit one row at 360px and should not try to. */
.weather .app-toolbar {
  flex-wrap: wrap;
  background: transparent;
  border-bottom: 0;
}

/* Capped on a desktop, where an unbounded select would stretch across the whole pane; it
   still shrinks on a phone. */
#weather-location {
  flex: 1 1 9rem;
  min-width: 0;
  min-height: var(--touch-min);
}

/* A row title that is a <label> (tapping it reaches the control) still lays out as the <p> it replaces. */
label.settings-row-title {
  display: block;
}

/* One rhythm between the cards, the gap the card idioms share. The two column wrappers
   stack on a phone; the desktop block below sets them side by side. */
.weather-body,
.weather-col {
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
}

.weather-col {
  min-width: 0;
}

/* Timers: the pane's body is one column of the add controls and the two collapsible groups,
   with the shared card gap between rows. The countdown is the row's big number, tabular so
   it does not jitter as digits change each second. A ringing timer or alarm takes an accent
   ring and the subtle panel ground. The switch is a native checkbox (role="switch") with its
   track drawn beside it, so the input keeps its own focus and keyboard behaviour. */
.timers-body,
.timers-add {
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
}

.timers-messages:empty {
  display: none;
}

/* The toolbar's own add controls: they take the free width and wrap, with Refresh kept at
   the end. An empty slot (a browser that cannot ring) takes no room. */
.timers-toolbar-controls {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  min-width: 0;
}

.timers-toolbar-controls:empty {
  display: none;
}

/* The toolbar is a card inside the field's own gutter, not the shared primitive's
   edge-to-edge band: the field already pads it at --list-gutter, so only the ground's
   square corners and bottom rule are zeroed and the card surface drawn in their place. */
.timers .app-toolbar {
  padding: var(--card-pad);
  border-bottom: 0;
  border-radius: var(--card-radius);
  box-shadow: var(--shadow-card);
}

.timers-quick,
.timers-days,
.timers-row-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.timers-form {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
}

.timers-field {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

/* Presets, repeat days and row actions all meet the touch floor and wrap with the text. */
.timers-quick > *,
.timers-days > *,
.timers-row-actions > * {
  min-height: var(--touch-min);
}

.timers-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
}

.timers-row-text {
  flex: 1 1 10rem;
  min-width: 0;
  overflow-wrap: break-word;
}

.timers-row-ringing {
  background: var(--panel-subtle);
  box-shadow: inset 0 0 0 2px var(--accent);
}

.timers-countdown,
.timers-alarm-time {
  margin: 0;
  font-size: calc(var(--text-detail-title) * 1.5);
  font-weight: var(--w-title);
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
}

.timers-switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-width: var(--touch-min);
  min-height: var(--touch-min);
  justify-content: center;
}

.timers-switch input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.timers-switch-track {
  position: relative;
  width: 2.4rem;
  height: 1.4rem;
  background: var(--line);
  border-radius: var(--radius-pill);
  transition: background var(--motion-press, 0.12s) ease;
}

.timers-switch-track::after {
  content: "";
  position: absolute;
  top: 0.2rem;
  left: 0.2rem;
  width: 1rem;
  height: 1rem;
  background: var(--muted);
  border-radius: 50%;
  transition: transform var(--motion-press, 0.12s) ease, background var(--motion-press, 0.12s) ease;
}

.timers-switch input:checked + .timers-switch-track {
  background: var(--accent);
}

.timers-switch input:checked + .timers-switch-track::after {
  background: var(--panel);
}

.timers-switch input:checked + .timers-switch-track::after {
  transform: translateX(1rem);
}

.timers-switch input:focus-visible + .timers-switch-track {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .timers-switch-track,
  .timers-switch-track::after {
    transition: none;
  }
}

/* Fixed heights, so the skeletons hold each panel's rough shape while the first read is
   in flight -- a stack of 1rem slivers would say nothing about what is coming. */
.weather-skeleton-now {
  height: 8rem;
}

.weather-skeleton-strip {
  height: 7rem;
}

.weather-skeleton-card {
  height: 7rem;
}

/* NOW: the condition icon, the one big temperature and the place it belongs to on one
   line; everything else reads beneath at the body step. The big figure is the pane's one
   deliberate departure from the three-step scale -- the same px clamp the page title's
   own larger figure uses, sized by the viewport so it fits a phone and leads a desktop
   column. */
/* The card is the containing block for its visually-hidden h2, which is position: absolute;
   without it that heading escapes the #weather scroller and lengthens the document. */
.weather-now {
  position: relative;
}

.weather-now-head {
  display: flex;
  align-items: center;
  gap: var(--space-r3);
}

.weather-now-head .weather-icon svg {
  width: 28px;
  height: 28px;
  stroke-width: 1.5;
}

.weather-now-temp {
  flex: 1 1 auto;
  min-width: 0;
}

.weather-now-temperature {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(calc(2.75rem * var(--text-scale)), 12vw, calc(3.25rem * var(--text-scale)));
  font-weight: var(--w-title);
  line-height: var(--leading-detail-tight);
  letter-spacing: 0;
  font-variant-numeric: proportional-nums;
}

.weather-now-unit {
  margin-left: var(--space-2xs);
  font-size: var(--text-detail-title);
  font-weight: var(--w-meta);
  letter-spacing: 0;
}

.weather-now-condition {
  margin: 0;
  color: var(--ink);
  font-size: var(--text-detail-body);
}

.weather-now-meta {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
  white-space: normal;
  overflow-wrap: break-word;
}

.weather-now-place,
.weather-now-summary,
.weather-now-wind,
.weather-now-fresh {
  margin: var(--space-r1) 0 0;
}

.weather-now-place,
.weather-now-fresh {
  color: var(--muted);
  font-size: var(--text-detail-meta);
}

/* The two alert states that never earn their own card -- checked and clear, and a country
   the alert service does not cover -- read as one quiet line above the attribution. */
.weather-alerts-quiet {
  margin: 0.2rem 0 0;
  color: var(--ink-on-wall-muted);
  font-size: var(--text-detail-meta);
  text-shadow: var(--text-shadow-on-wall);
}

/* The unsaved-location banner: the sentence and its Retry save button on one wrapping row. */
.weather-save-failed {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem var(--space-r3);
}

.weather-save-failed-text {
  flex: 1 1 12rem;
  margin: 0;
}

/* ALERTS: one row per alert, the severity as a word in a tag and the tone as a left
   border -- colour and text together, never one standing in for the other. */
.weather-alert-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-r2);
  padding: var(--space-r2) 0;
}

.weather-alert-icon {
  display: flex;
  flex: none;
  margin-top: 3px;
  color: var(--warn);
}

.weather-alert-extreme,
.weather-alert-severe {
  border-left: 3px solid var(--error);
  padding-left: 0.6rem;
}

.weather-alert-moderate {
  border-left: 3px solid var(--warn);
  padding-left: 0.6rem;
}

.weather-alert-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.2rem 0.4rem;
  margin: 0;
  font-size: var(--text-detail-body);
}

.weather-alert-until {
  color: var(--muted);
  font-size: var(--text-detail-meta);
}

.weather-alert-headline {
  margin: 0.2rem 0 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
}

.weather-alert-unavailable {
  margin: 0;
  font-size: var(--text-detail-body);
}

.weather-alert-details {
  margin: var(--space-r1) 0 0;
}

/* The service's own wording, kept exactly as issued: pre-wrap so its line breaks and
   capitalisation survive being poured into a card. */
.weather-alert-description,
.weather-alert-instruction {
  margin: var(--space-r1) 0 0;
  white-space: pre-wrap;
}

.weather-alert-source {
  color: var(--accent);
  font-size: var(--text-detail-meta);
}

/* NEAR TERM: the chart glances, the list records. The strip scrolls horizontally on a
   phone with the overscroll contained, so a swipe on the chart does not take the pane
   with it; the text list under it never scrolls, because it wraps. */
.weather-near {
  margin-bottom: var(--space-r2);
}

.weather-near-qualifier,
.weather-near-measure,
.weather-near-scale,
.weather-near-missing {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
}

.weather-near-summary {
  margin: 0;
  color: var(--ink);
  font-size: var(--text-detail-body);
}

.weather-near-resolution {
  margin: var(--space-r1) 0 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
}

.weather-near-missing {
  margin-top: var(--space-r1);
}

.weather-near-list-title {
  margin: 0.6rem 0 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
  font-weight: var(--w-title);
}

.weather-near-scroll {
  position: relative;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

/* The horizontal scrollers fade at the right edge while there is more to scroll to. */
.weather-near-scroll[data-more-right],
.weather-hourly-scroll[data-more-right] {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent);
}

/* The chart is fixed-geometry HTML, not a scaling graphic: eight columns of at least 38px
   over a 64px plot, so a 360px phone scrolls it instead of squashing it (the script sets
   the minimum width from the column count). */
.weather-near-chart {
  padding-top: 1.1rem;
  color: var(--muted);
  font-size: var(--text-detail-meta);
  font-variant-numeric: tabular-nums;
}

.weather-near-more {
  margin-top: var(--space-r1);
  padding-top: var(--space-r1);
}

.weather-near-cols {
  position: relative;
  display: grid;
}

/* The now marker: a 2px line over the plot height, on the left edge above the 'Now' tick. */
.weather-near-now {
  position: absolute;
  top: 0;
  left: 0;
  height: 64px;
  width: 2px;
  background: var(--accent);
  pointer-events: none;
}

.weather-near-now-label {
  position: absolute;
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  color: var(--accent);
  font-size: var(--text-detail-meta);
  line-height: 1;
}

.weather-near-axis {
  position: relative;
  height: 1.2rem;
  margin-top: var(--space-r1);
  color: var(--muted);
  font-size: var(--text-detail-meta);
  font-variant-numeric: tabular-nums;
}

.weather-near-tick {
  position: absolute;
  top: 0;
  white-space: nowrap;
}

.weather-near-col {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* The bottom border is the baseline, continuous across the columns. */
.weather-near-plot {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  height: 64px;
  border-bottom: 1px solid var(--line-strong);
}

.weather-near-bar {
  width: 60%;
  max-width: 28px;
  background: var(--weather-rain);
}

.weather-near-bar-light {
  background: color-mix(in srgb, var(--weather-rain) 60%, transparent);
}

.weather-near-bar-heavy {
  background: color-mix(in srgb, var(--weather-rain) 75%, var(--ink));
}

/* An unknown interval: a full-height hatched bar, never a bar at zero. */
.weather-near-nodata {
  width: 60%;
  max-width: 28px;
  height: 100%;
  background: repeating-linear-gradient(135deg, color-mix(in srgb, var(--muted) 45%, transparent) 0 2px, transparent 2px 6px);
}

.weather-near-list {
  margin: var(--space-r2) 0 0;
  padding: 0;
  list-style: none;
  font-variant-numeric: tabular-nums;
}

.weather-near-entry {
  padding: 0.3rem 0;
}

.weather-near-note {
  margin: 0.4rem 0 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
}

/* The one shared size for a condition glyph, wherever one renders. */
.weather-icon {
  display: flex;
  flex: none;
  color: var(--icon-gold);
}

.weather-icon svg {
  width: 20px;
  height: 20px;
  stroke-width: 1.7;
}

/* TODAY WEATHER: a compact, borderless block -- low, current and high, then the condition
   changes of the next hours as icons joined by bars -- right-aligned beside Today's clock.
   A slot with nothing to show is hidden; the block is one tap target, and text wraps,
   never truncates, so it may grow past the reserved minimum. */
.today-weather-slot {
  flex: none;
  min-height: 48px;
}

.today-weather-slot[hidden] {
  display: none;
}

.today-weather-skeleton {
  width: 11.5rem;
  max-width: 100%;
  height: 48px;
  margin-left: auto;
  border-radius: var(--card-radius);
}

:root[data-text-size="large"] .today-weather-slot {
  min-height: 64px;
}

:root[data-text-size="large"] .today-weather-skeleton {
  height: 64px;
}

:root[data-text-size="large"] .today-weather-card {
  min-height: 64px;
}

.today-weather-card {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-r1);
  box-sizing: border-box;
  width: 11.5rem;
  max-width: 100%;
  min-height: 48px;
  margin-left: auto;
  padding: 0;
  border: 0;
  background: none;
  /* Set on the wallpaper like the clock and date line, so the on-wall inks in both themes. */
  color: var(--ink-heading);
  text-shadow: var(--text-shadow-on-wall);
  font: inherit;
  text-align: right;
  cursor: pointer;
}

.today-weather-temps {
  display: flex;
  align-items: baseline;
  justify-content: flex-end;
  gap: var(--space-r2);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.today-weather-temps[hidden],
.today-weather-timeline[hidden],
.today-weather-message[hidden],
.today-weather-freshness[hidden] {
  display: none;
}

.today-weather-temperature {
  color: var(--ink-heading);
  font-family: var(--font-display);
  /* Display numeral: px like .weather-now-temperature's, not a new detail-text rem step. */
  font-size: calc(1.125rem * var(--text-scale));
  font-weight: var(--w-title);
  line-height: 1.1;
  font-variant-numeric: proportional-nums;
}

.today-weather-low,
.today-weather-high {
  color: var(--ink-on-wall-muted);
  font-size: var(--text-caption);
}

.today-weather-low[hidden],
.today-weather-high[hidden] {
  display: none;
}

.today-weather-timeline {
  display: flex;
  align-items: flex-start;
  gap: var(--space-r1);
  min-width: 0;
}

.today-weather-timeline .today-weather-bar {
  height: 3px;
}

.today-weather-timeline-steady {
  align-items: center;
  justify-content: flex-end;
  gap: 0.375rem;
  color: var(--ink-on-wall-muted);
  font-size: var(--text-detail-meta);
}

/* A run grows in proportion to its hours (flex-grow is set inline); the floor is sized
   to the caption-size time label. */
.today-weather-step {
  display: flex;
  flex: 1 1 0;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.125rem;
  min-width: calc(var(--text-caption) * 3.25);
  text-align: left;
}

.today-weather-step .weather-icon svg,
.today-weather-timeline-steady .weather-icon svg {
  display: block;
  width: 15px;
  height: 15px;
}

.today-weather-step-time {
  color: var(--ink-on-wall-muted);
  font-size: var(--text-caption);
  line-height: 1.2;
  white-space: nowrap;
}

.today-weather-bar {
  align-self: stretch;
  height: 0.25rem;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--ink-on-wall-muted) 70%, transparent);
}

.today-weather-message {
  display: flex;
  flex-direction: column;
  gap: 0.125rem;
}

.today-weather-message-title {
  font-size: var(--text-detail-body);
  line-height: 1.25;
}

.today-weather-message-line {
  color: var(--ink-on-wall-muted);
  font-size: var(--text-detail-meta);
  line-height: 1.25;
}

.today-weather-freshness {
  color: var(--ink-on-wall-muted);
  font-size: var(--text-detail-meta);
  line-height: 1.25;
}

/* One line of parts joined by a dot that is CSS-only: each .dot-part draws its own leading
   dot in a --dot-sep-wide slot, and the .dot-row is pulled left by that width inside a
   .dot-line that clips horizontally -- so the part that starts a wrapped line has its dot in
   the clipped slot and no separator is ever stranded at a line edge. overflow-x: clip leaves
   the vertical axis alone, so descenders and focus outlines are not cut. */
.dot-line {
  --dot-sep: 0.75rem;
  display: block;
  min-width: 0;
  overflow-x: clip;
}

.dot-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  margin-left: calc(-1 * var(--dot-sep));
}

.dot-part {
  display: flex;
  box-sizing: border-box;
  align-items: baseline;
  min-width: 0;
  max-width: 100%;
  white-space: normal;
}

.dot-part::before {
  content: '·';
  flex: none;
  width: var(--dot-sep);
  font-weight: normal;
  line-height: 1;
  text-align: center;
}

.dot-part:empty,
.dot-part[hidden] {
  display: none;
}

.weather-now-part,
.today-weather-part {
  white-space: nowrap;
}

.today-weather-outlook-text {
  flex: 1 1 auto;
  font-size: var(--text-detail-body);
  line-height: 1.25;
  overflow-wrap: anywhere;
}

.today-weather-outlook-until {
  white-space: nowrap;
}

.today-weather-outlook {
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  gap: var(--space-sm);
  min-width: 0;
  text-align: left;
}

.today-weather-outlook[hidden] {
  display: none;
}

.today-weather-outlook-alert {
  border-left: 3px solid var(--error);
  padding-left: 0.4rem;
}

.today-weather-alert-icon {
  display: flex;
  flex: none;
  color: var(--warn);
}

.today-weather-alert-icon[hidden] {
  display: none;
}

.today-weather-alert-icon svg {
  width: 18px;
  height: 18px;
}

/* HOURLY: a strip the scroller owns, focusable so it is reachable from a keyboard. */
.weather-hourly-scroll {
  position: relative;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.weather-hourly-list {
  display: flex;
  width: max-content;
  margin: 0;
  padding: 0.1rem 0.1rem 0.35rem;
  list-style: none;
}

.weather-hour {
  position: relative;
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: center;
  gap: 0.15rem;
  min-width: 3.75rem;
  padding: 0.2rem 0.2rem 0;
  text-align: center;
}

:root[data-text-size="large"] .weather-hour {
  min-width: 5rem;
}

.weather-hour-condition {
  position: relative;
  display: flex;
}

.weather-hour-time {
  color: var(--muted);
  font-size: var(--text-detail-meta);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.weather-hour-temp {
  font-size: var(--text-detail-body);
  font-variant-numeric: tabular-nums;
}

.weather-hour-pop {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  min-height: 1rem;
  color: var(--muted);
  font-size: var(--text-detail-meta);
}

.weather-hour-drop {
  display: flex;
  color: var(--weather-rain);
}

.weather-hour-drop svg {
  width: 13px;
  height: 13px;
}

/* DAILY: seven days as ONE grouped surface -- each group is a day's row button over its own
   collapsible detail, the hairline between groups being .app-divider-list's own, no per-row cards. The expand is a plain
   hidden toggle with no transition of its own anywhere, so prefers-reduced-motion needs
   no override here -- nothing moves except the region appearing. The card is a size
   container, so the two-line layout follows the card's width, not the viewport's. */
.weather-daily {
  container-type: inline-size;
}

.weather-day {
  display: grid;
  grid-template-columns: 6.5em 20px minmax(0, 1fr) auto auto;
  align-items: center;
  column-gap: 0.6rem;
  min-height: 48px;
  font-variant-numeric: tabular-nums;
}

.weather-day-name {
  min-width: 0;
  font-weight: var(--w-title);
  white-space: nowrap;
}

.weather-day-short {
  display: none;
}

.weather-day-condition {
  min-width: 0;
  overflow-wrap: break-word;
}

.weather-day-temps {
  display: block;
  text-align: right;
  white-space: nowrap;
}

.weather-day-range {
  display: block;
  position: relative;
  height: 0.25rem;
  margin-top: var(--space-2xs);
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--muted) 20%, transparent);
  overflow: hidden;
}

.weather-day-range-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: var(--radius-pill);
  background: linear-gradient(90deg, var(--range-from, var(--muted)), var(--range-to, var(--muted)));
}

.weather-day-high {
  color: var(--ink);
  white-space: nowrap;
}

.weather-day-low {
  color: var(--muted);
  white-space: nowrap;
}

.weather-day-pop {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2xs);
  min-width: 3.4em;
  color: var(--muted);
  font-size: var(--text-detail-meta);
  white-space: nowrap;
}

.weather-day-drop {
  display: flex;
  color: var(--weather-rain);
}

.weather-day-drop svg {
  width: 13px;
  height: 13px;
}

/* A narrow card shows the short weekday, which frees the room the condition needs. */
@container (max-width: 30rem) {
  .weather-day-long {
    display: none;
  }

  .weather-day-short {
    display: inline;
  }
}

/* Large text or a very narrow phone: each day reads as two lines -- day and condition on the
   first, high/low and precipitation on the second -- not five squeezed columns. Children are
   name, icon, condition, temps, precipitation. */
:root[data-text-size="large"] .weather-day {
  grid-template-columns: 20px auto minmax(0, 1fr) auto;
  row-gap: 0.15rem;
}

:root[data-text-size="large"] .weather-day > :nth-child(1) { grid-column: 2; grid-row: 1; }
:root[data-text-size="large"] .weather-day > :nth-child(2) { grid-column: 1; grid-row: 1 / span 2; }
:root[data-text-size="large"] .weather-day > :nth-child(3) { grid-column: 3 / -1; grid-row: 1; }
:root[data-text-size="large"] .weather-day > :nth-child(4) { grid-column: 2 / 4; grid-row: 2; }
:root[data-text-size="large"] .weather-day > :nth-child(5) { grid-column: 4; grid-row: 2; }

@container (max-width: 30rem) {
  .weather-day {
    grid-template-columns: 20px auto minmax(0, 1fr) auto;
    row-gap: 0.15rem;
    column-gap: 0.4rem;
  }

  .weather-day > :nth-child(1) { grid-column: 2; grid-row: 1; }
  .weather-day > :nth-child(2) { grid-column: 1; grid-row: 1 / span 2; }
  .weather-day > :nth-child(3) { grid-column: 3 / -1; grid-row: 1; }
  .weather-day > :nth-child(4) { grid-column: 2 / 4; grid-row: 2; }
  .weather-day > :nth-child(5) { grid-column: 4; grid-row: 2; }
}

.weather-day-detail {
  padding: 0.15rem 0.3rem 0.55rem;
}

.weather-day-detail-line {
  margin: 0.15rem 0 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
  font-variant-numeric: tabular-nums;
}

/* DETAILS: four label-and-value pairs, as many to a row as the card has room for. */
.weather-details-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-r2) var(--space-r4);
  margin: 0;
}

:root[data-text-size="large"] .weather-details-grid {
  grid-template-columns: minmax(0, 1fr);
}

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

.weather-detail-label {
  margin: 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
}

.weather-detail-value {
  margin: 0.05rem 0 0;
  overflow-wrap: break-word;
  font-variant-numeric: tabular-nums;
}

/* RADAR: an on-demand card. The map is a square viewport (up to 420px) over a 3x3 block of
   tiles the script sizes and offsets in percentages, so the location sits at its centre at
   any card width; the radar layer is the translucent one over the basemap. Nothing on it
   animates or transitions -- playback is the script stepping frames, never a CSS motion. */
.weather-radar-note {
  margin: 0.3rem 0 0.6rem;
}

.weather-radar-map {
  position: relative;
  width: 100%;
  max-width: 420px;
  aspect-ratio: 1;
  overflow: hidden;
  background: var(--panel);
  border-radius: var(--radius-control);
}

.weather-radar-block {
  position: absolute;
}

.weather-radar-layer {
  position: absolute;
  inset: 0;
}

.weather-radar-layer-radar {
  opacity: 0.75;
}

.weather-radar-tile {
  position: absolute;
  display: block;
  max-width: none;
  user-select: none;
}

.weather-radar-marker {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 14px;
  height: 14px;
  box-sizing: border-box;
  border: 3px solid var(--accent);
  border-radius: 50%;
  background: var(--panel-subtle);
  transform: translate(-50%, -50%);
  pointer-events: none;
}

.weather-radar-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  max-width: 420px;
  margin-top: 0.6rem;
}

.weather-radar-controls .app-quiet-button {
  transition: none;
}

.weather-radar-frame {
  margin: var(--space-r2) 0 0;
  font-variant-numeric: tabular-nums;
}

.weather-radar-stale {
  margin: 0.3rem 0 0;
}

.weather-radar-stale[hidden] {
  display: none;
}

.weather-radar-attribution {
  margin-top: 0.6rem;
}

.weather-attribution {
  margin: 0.2rem 0 0;
  color: var(--muted);
  font-size: var(--text-detail-meta);
}

.weather-attribution-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  color: var(--accent);
}

/* SETUP: the first-run card, and the places manager that replaces it once a home exists.
   Both draw the one search-row shape: a field that grows and a Search button that does
   not. */
.weather-setup-locate {
  margin-top: var(--space-r3);
  /* Wrap under Large text instead of overflowing the pane scroller. */
  max-width: 100%;
  white-space: normal;
}

.weather-places-list {
  display: flex;
  flex-direction: column;
  margin-bottom: var(--space-r3);
}

.weather-place-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0;
}

.weather-place-name {
  flex: 1 1 auto;
  min-width: 0;
}

.weather-retry {
  display: flex;
  justify-content: center;
}

/* Desktop: the body becomes a two-column grid of the two column wrappers -- now, alerts,
   near and hourly in the wide one, the week, details and radar in the narrow one, both
   starting at the top. The wrappers keep the DOM order the phone stack reads in. The
   setup and retry cards and the attribution span both columns. */
@media (min-width: 60rem) {
  .weather-body {
    display: grid;
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
    align-items: start;
    width: 100%;
    max-width: 72rem;
    margin-inline: auto;
  }

  .weather-setup,
  .weather-retry,
  .weather-save-failed,
  .weather-alerts-quiet,
  .weather-attribution {
    grid-column: 1 / -1;
  }
}

/* Phone: compact enough that the header, the Now card, the next-two-hours chart and the
   start of the hourly strip sit above the fold at 390x844. Type is not shrunk; the room
   comes from padding, gaps and moving lines into shared rows. */
@media (max-width: 47.99rem) {
  .weather {
    --card-pad-y: 10px;
    --card-pad-x: 14px;
    --card-pad: var(--card-pad-y) var(--card-pad-x);
    --card-gap: 8px;
  }

  /* Basis 100% (the shared slot's own) keeps the last-updated line wrapping below the title
     row, so the gear's auto margin has the free space and sits at the right edge. */
  .weather .app-page-header-subtitle {
    flex: 1 1 100%;
    min-width: 0;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    line-height: 1.3;
  }

  .weather .app-toolbar {
    flex-wrap: wrap;
    padding-block: 0.2rem;
    padding-inline: 0;
  }

  .weather .app-toolbar-title {
    display: none;
  }

  #weather-location {
    flex: 1 1 9rem;
    min-width: 0;
  }

  #weather-status {
    margin: 0.1rem 0;
  }

  #weather-status:empty {
    display: none;
  }

  .weather .app-section-label {
    margin-bottom: 0.3rem;
  }
}

[data-weather-tone="sun"] {
  color: var(--weather-sun);
}

[data-weather-tone="cloud"] {
  color: var(--weather-cloud);
}

[data-weather-tone="rain"] {
  color: var(--weather-rain);
}

[data-weather-tone="snow"] {
  color: var(--weather-snow);
}

[data-weather-tone="storm"] {
  color: var(--weather-storm);
}

[data-weather-tone="fog"] {
  color: var(--weather-fog);
}

[data-temp="cold"] {
  color: var(--weather-temp-cold);
}

[data-temp="mild"] {
  color: var(--weather-temp-mild);
}

[data-temp="warm"] {
  color: var(--weather-temp-warm);
}

[data-temp="hot"] {
  color: var(--weather-temp-hot);
}

[data-pop="low"] {
  color: var(--weather-rain-low);
}

[data-pop="mid"] {
  color: var(--weather-rain-mid);
}

[data-pop="high"] {
  color: var(--weather-rain);
}
