/* Tiện ích (clock + weather) pane — owned by js/hub.js. Tokens/components from base.css; every class here starts with hub-. */

/* ---------- header ---------- */
.hub-title { flex: 0 1 auto; min-width: 0; font-size: 1.1em; font-weight: 700; color: var(--text); }
.hub-refresh { margin-left: auto; }
.hub-refresh.is-spinning .icon { animation: hub-spin .9s linear infinite; }
@keyframes hub-spin { to { transform: rotate(360deg); } }

/* ---------- root: a grid whose areas change with the pane shape (data-flow) ---------- */
/* hub.js sets --hub-w / --hub-h (px) and walks data-size / data-chips / data-trim down until nothing overflows. */
.hub, .hub-search {
  --hub-pad: clamp(10px, 1.8vmin, 20px);
  --hub-gap: clamp(8px, 1.3vmin, 14px);
}
.hub {
  --hub-cw: var(--hub-w);                          /* rough width / height of the weather card, for type sizes */
  --hub-ch: calc(var(--hub-h) * .6);
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto 1fr auto;
  grid-template-areas: "clock" "wx" "places";
  gap: var(--hub-gap);
  padding: var(--hub-pad);
  overflow-x: hidden;
  overflow-y: auto;
  background: var(--surface);
}
.hub[data-flow="row"] {
  --hub-cw: calc(var(--hub-w) * .66);
  --hub-ch: var(--hub-h);
  grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  grid-template-rows: auto auto;                   /* auto, not 1fr: a spanning card would not get its minimum height from a flexible track */
  grid-template-areas: "clock wx" "places wx";
}
.hub[data-flow="row"] .hub-places { align-self: end; }
.hub[data-flow="row"][data-chips="none"] .hub-clock { grid-row: 1 / 3; }

.hub.is-covered { visibility: hidden; }              /* the search dialog is on top of it */

/* ---------- clock ---------- */
.hub-clock {
  grid-area: clock;
  align-self: center;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.hub-clock__time {
  font-size: min(clamp(30px, min(calc(var(--hub-w) * .2), calc(var(--hub-h) * .16)), 168px), calc(var(--hub-w) * .24));   /* never wider than the pane */
  font-weight: 700;
  line-height: 1;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.hub-clock__date {
  margin-top: .3em;
  font-size: clamp(15px, calc(var(--hub-w) * .045), 24px);
  font-weight: 500;
  line-height: 1.25;
  color: var(--text-2);
}
.hub[data-flow="row"] .hub-clock__time { font-size: min(clamp(30px, min(calc(var(--hub-w) * .1), calc(var(--hub-h) * .26)), 150px), calc(var(--hub-w) * .1)); }
.hub[data-flow="row"] .hub-clock__date { font-size: clamp(15px, calc(var(--hub-w) * .02), 24px); }

/* ---------- weather card ---------- */
/* Sky = hue / saturation per condition; lightness per theme and day / night. */
.hub {
  --sky-h: 220; --sky-s: 18%;
  --sky-l1: 22%; --sky-l2: 14%;
  --glow: transparent;
}
.hub[data-sky="clear"] { --sky-h: 210; --sky-s: 66%; }
.hub[data-sky="partly"] { --sky-h: 213; --sky-s: 46%; }
.hub[data-sky="cloudy"] { --sky-h: 216; --sky-s: 20%; }
.hub[data-sky="fog"] { --sky-h: 200; --sky-s: 14%; }
.hub[data-sky="drizzle"] { --sky-h: 208; --sky-s: 32%; }
.hub[data-sky="rain"] { --sky-h: 214; --sky-s: 42%; }
.hub[data-sky="snow"] { --sky-h: 204; --sky-s: 34%; }
.hub[data-sky="storm"] { --sky-h: 256; --sky-s: 34%; }
.hub:not([data-sky="none"]) { --sky-l1: 25%; --sky-l2: 15%; }
.hub[data-day="0"]:not([data-sky="none"]) { --sky-l1: 18%; --sky-l2: 9%; }
.hub[data-day="0"][data-sky="clear"] { --sky-h: 232; --sky-s: 50%; }
.hub[data-day="0"][data-sky="partly"] { --sky-h: 228; --sky-s: 36%; }
.hub[data-day="1"][data-sky="clear"] { --glow: hsl(42 100% 62% / .12); }
.hub[data-day="1"][data-sky="partly"] { --glow: hsl(42 100% 70% / .1); }
.hub[data-day="0"][data-sky="clear"], .hub[data-day="0"][data-sky="partly"] { --glow: hsl(220 90% 80% / .1); }
html[data-theme="light"] .hub:not([data-sky="none"]) { --sky-l1: 93%; --sky-l2: 84%; }
html[data-theme="light"] .hub[data-day="0"]:not([data-sky="none"]) { --sky-l1: 88%; --sky-l2: 80%; }
html[data-theme="light"] .hub[data-sky="none"] { --sky-l1: 96%; --sky-l2: 92%; }
html[data-theme="light"] .hub[data-day="1"][data-sky="clear"] { --glow: hsl(42 100% 62% / .4); }
html[data-theme="light"] .hub[data-day="1"][data-sky="partly"] { --glow: hsl(42 100% 62% / .25); }
html[data-theme="light"] .hub[data-day="0"][data-sky="clear"],
html[data-theme="light"] .hub[data-day="0"][data-sky="partly"] { --glow: hsl(225 90% 70% / .16); }

.hub-wx {
  grid-area: wx;
  position: relative;
  min-width: 0;                                    /* no overflow / min-height:0 here: the card's content height must reach the root, hub.js measures it */
  display: flex;
  flex-direction: column;
  gap: var(--hub-gap);
  padding: clamp(10px, 1.7vmin, 18px);
  border-radius: var(--radius);
  color: var(--text);
  line-height: 1.2;
  --hub-temp: clamp(32px, min(calc(var(--hub-cw) * .2), calc(var(--hub-ch) * .22)), 120px);   /* type sizes shared by the reading column and its fixed width */
  --hub-cond: clamp(16px, min(calc(var(--hub-cw) * .05), calc(var(--hub-ch) * .16)), 26px);
  --hub-u: clamp(15px, calc(var(--hub-cw) * .022), 24px);                                      /* type unit of tiles and hours: 15 px floor, grows on big panes */
  background:
    radial-gradient(90% 80% at 100% 0%, var(--glow), transparent 65%),
    linear-gradient(155deg, hsl(var(--sky-h) var(--sky-s) var(--sky-l1)), hsl(var(--sky-h) var(--sky-s) var(--sky-l2)));
}

.hub-wx__head {
  flex: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 2px 10px;
  min-width: 0;
  font-weight: 600;
}
.hub-wx__place { max-width: 100%; font-size: 1.05em; font-weight: 700; color: var(--text); }
.hub-wx__status { min-width: 0; max-width: 100%; display: inline-flex; align-items: flex-start; gap: 6px; margin-left: auto; color: var(--text-2); font-weight: 500; text-align: right; }
.hub-wx__status-icon { flex: none; display: inline-flex; }
.hub-wx__status-icon .icon { --icon: 18px; }
.hub[data-state="stale"] .hub-wx__status {
  padding: 3px 12px 3px 8px;
  border-radius: 14px;
  border: 1px solid var(--warn);
  background: var(--surface);
  color: var(--text);
  font-weight: 700;
}
.hub[data-state="stale"] .hub-wx__status-icon { color: var(--warn); }

/* auto margins centre the content when there is room and simply collapse when there is none (no overlap) */
.hub-wx__main {
  flex: 0 1 auto;
  margin: auto 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--hub-gap) calc(var(--hub-gap) * 2);
}
.hub[data-state="loading"] .hub-wx__main { opacity: .55; }

.hub-wx__now { flex: 0 1 auto; display: flex; align-items: center; gap: clamp(10px, 2vmin, 20px); }
.hub-wx__icon { --icon: clamp(36px, min(calc(var(--hub-cw) * .17), calc(var(--hub-ch) * .3)), 112px); flex: none; }
.hub-wx__reading { width: max(calc(var(--hub-temp) * 1.8), calc(var(--hub-cond) * 6.5)); }   /* fixed: "–" while loading and "28" later take the same room */
.hub-wx__temp {
  margin: 0;
  font-size: var(--hub-temp);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.hub-wx__unit { margin-left: 2px; font-size: .42em; font-weight: 600; vertical-align: top; color: var(--text-2); letter-spacing: 0; }
.hub-wx__cond { margin: .25em 0 0; font-size: var(--hub-cond); font-weight: 600; }

/* weather glyph colours: the sun stays warm, everything else follows the text */
.hub-ico { display: block; color: var(--text); }
.hub-ico[data-icon="sun"] { color: var(--warn); }
.hub-wx__stats {
  flex: 1 1 230px;
  min-width: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.hub-stat, .hub-hour { position: relative; isolation: isolate; border: 1px solid var(--border); border-radius: 14px; }
.hub-stat::before, .hub-hour::before {              /* translucent tile made of the theme's own surface colour */
  content: "";
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  z-index: -1;
  border-radius: inherit;
  background: var(--surface);
  opacity: .45;
}
html[data-theme="light"] .hub-stat::before, html[data-theme="light"] .hub-hour::before { opacity: .6; }
.hub-stat { flex: 1 1 0; min-width: max(112px, 7.5em); padding: .35em .8em .4em; font-size: var(--hub-u); }
.hub-stat[data-extra="yes"] { min-width: max(172px, 9.5em); }
.hub-stat__label { display: flex; align-items: center; gap: .4em; margin: 0; font-weight: 500; color: var(--text-2); white-space: nowrap; }
.hub-stat__icon { flex: none; display: inline-flex; }
.hub-stat__icon .icon { --icon: 1.2em; }
.hub-stat__value { margin: 0; font-size: 1.2em; font-weight: 700; white-space: nowrap; font-variant-numeric: tabular-nums; }

.hub-wx__hours {
  flex: 1 1 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  gap: 4px;
  overflow-x: auto;
  scrollbar-width: none;
}
.hub-wx__hours::-webkit-scrollbar { display: none; }
.hub-hour { flex: 1 0 38px; display: grid; justify-items: center; gap: .1em; padding: .3em 2px; font-size: var(--hub-u); }
.hub-hour__time { color: var(--text-2); font-variant-numeric: tabular-nums; }
.hub-hour__icon { --icon: 1.9em; }
.hub-hour__temp { font-size: 1.15em; font-weight: 700; font-variant-numeric: tabular-nums; }
.hub-hour__rain { min-height: 1.2em; color: var(--text-2); font-variant-numeric: tabular-nums; }

/* nothing to show and the request failed */
.hub-wx__fail { display: none; flex: 1 1 auto; flex-direction: column; align-items: center; justify-content: center; gap: 10px; text-align: center; }
.hub-wx__fail-icon .icon { --icon: 44px; color: var(--text-2); }
.hub-wx__fail-text { max-width: 28em; margin: 0; color: var(--text); font-weight: 600; }
.hub[data-state="error"] .hub-wx__fail { display: flex; }
.hub[data-state="error"] .hub-wx__main,
.hub[data-state="error"] .hub-wx__status { display: none; }

/* ---------- place chips ---------- */
.hub-places {                                       /* padding = room for the focus ring inside the scroller; min-height: a scroller's track would otherwise collapse */
  grid-area: places;
  min-width: 0;
  min-height: calc(max(44px, var(--tap) - 4px) + 8px);
  padding: 4px;
  margin: -4px;
  scroll-snap-type: none;                          /* revealChip() scrolls to exact positions; snapping would jump a whole chip */
}
.hub-places .chip { min-height: max(44px, calc(var(--tap) - 4px)); }
.hub-places.has-left { -webkit-mask-image: linear-gradient(90deg, transparent, #000 28px); mask-image: linear-gradient(90deg, transparent, #000 28px); }
.hub-places.has-right { -webkit-mask-image: linear-gradient(270deg, transparent, #000 28px); mask-image: linear-gradient(270deg, transparent, #000 28px); }
.hub-places.has-left.has-right {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 28px, #000 calc(100% - 28px), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 28px, #000 calc(100% - 28px), transparent);
}
.hub-chip-icon { display: inline-flex; }
.hub-places .is-busy .hub-chip-icon .icon { animation: hub-spin .9s linear infinite; }

.hub-find { min-width: max(44px, calc(var(--tap) - 4px)); padding: 0; justify-content: center; border-style: dashed; }   /* icon only: leaves room for the city chips */

/* ---------- place search (a layer over the whole pane body) ---------- */
.hub-search { padding: var(--hub-pad); }
.hub-search__bar { display: flex; align-items: center; gap: 8px; }
.hub-search__status { margin: var(--hub-gap) 2px; min-height: 1.4em; color: var(--text-2); }
.hub-search__retry { margin-bottom: var(--hub-gap); }
.hub-search .field .icon-btn { width: 44px; height: 44px; }
.hub-results { margin: 0; padding: 0; list-style: none; display: grid; gap: 8px; }
.hub-result {
  width: 100%;
  min-height: 56px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 2px;
  padding: 8px 16px;
  border: 1px solid var(--border);
  border-radius: 14px;
  background: var(--surface-2);
  color: var(--text);
  text-align: left;
  transition: background-color .15s, transform .1s;
}
.hub-result:hover { background: var(--surface-3); }
.hub-result:active { transform: scale(.98); }
.hub-result strong { max-width: 100%; font-size: 1.1em; }
.hub-result__region { max-width: 100%; color: var(--text-2); }

/* ---------- transient message over the chips (location denied …) ---------- */
.hub-note {                                         /* floats just above the chip row so the chips stay tappable */
  position: absolute;
  left: var(--hub-pad); right: var(--hub-pad);
  bottom: calc(var(--hub-pad) + max(44px, var(--tap) - 4px) + 8px + var(--hub-gap));
  z-index: 3;
  align-items: center;
  padding: 4px 4px 4px 14px;
  background: var(--surface-2);
  box-shadow: var(--shadow);
}
.hub[data-chips="none"] .hub-note { bottom: var(--hub-pad); }
.hub-note__icon { display: inline-flex; }
.hub-note__text { flex: 1 1 auto; min-width: 0; margin: 0; }

/* ---------- how much is shown (data-size / data-chips / data-trim, chosen by hub.js) ---------- */
.hub[data-size="xs"] .hub-wx__stats,
.hub[data-size="xs"] .hub-wx__hours,
.hub[data-size="s"] .hub-wx__hours,
.hub[data-size="s"] .hub-stat[data-extra="yes"],
.hub[data-size="m"] .hub-stat[data-extra="yes"] { display: none; }
.hub[data-size="s"] .hub-stat { min-width: 80px; padding-right: .5em; padding-left: .5em; }
.hub[data-size="s"] .hub-stat__icon { display: none; }
.hub[data-chips="none"] .hub-places { display: none; }
.hub[data-chips="wrap"] .hub-places { flex-wrap: wrap; overflow: visible; }
.hub[data-trim="head"] .hub-clock__date,
.hub[data-trim="head"] .hub-wx__place,
.hub[data-trim="head"] .hub-wx__status > :last-child,
.hub[data-trim="all"] .hub-clock__date,
.hub[data-trim="all"] .hub-wx__place,
.hub[data-trim="all"] .hub-wx__status > :last-child,
.hub[data-trim="all"] .hub-wx__cond,
.hub[data-trim="min"] .hub-clock__date,
.hub[data-trim="min"] .hub-wx__place,
.hub[data-trim="min"] .hub-wx__status > :last-child,
.hub[data-trim="min"] .hub-wx__cond,
.hub[data-trim="min"] .hub-wx__icon,
.hub[data-trim="min"] .hub-wx__unit { display: none; }
/* trimmed: the header line goes, only the "old data" marker survives in the card corner */
.hub:not([data-trim="none"]) .hub-wx__head { position: absolute; top: 6px; right: 8px; }
.hub:not([data-trim="none"])[data-state="ready"] .hub-wx__head,
.hub:not([data-trim="none"])[data-state="loading"] .hub-wx__head { display: none; }
.hub:not([data-trim="none"])[data-state="stale"] .hub-wx__status { padding: 3px; }
.hub[data-trim="all"], .hub[data-trim="min"] { --hub-pad: 8px; --hub-gap: 6px; }
.hub[data-trim="all"] .hub-wx, .hub[data-trim="min"] .hub-wx { padding: 6px 12px; }
.hub[data-trim="min"] { --hub-pad: 6px; }
.hub[data-trim="min"] .hub-wx { padding: 3px 10px; }
.hub[data-trim="all"] .hub-wx { --hub-temp: clamp(32px, calc(var(--hub-ch) * .45), 120px); }
.hub[data-trim="all"] .hub-wx__icon { --icon: clamp(32px, calc(var(--hub-ch) * .45), 112px); }
.hub[data-trim="min"] .hub-wx { --hub-temp: clamp(26px, min(calc(var(--hub-cw) * .3), calc(var(--hub-ch) * .45)), 80px); }
.hub[data-trim="min"] .hub-wx__reading { width: auto; }
