/**
 * Global Weather Pro - Main Styles
 * Theme loader and base styles for the weather widget
 * 
 * Theme System:
 * - Dark Theme: gwpro-dark-theme.css
 * - Light Theme: gwpro-light-theme.css
 * - Alert Styles: alert-icon-styles.css
 */

/* ============================================= */
/* Global Reset & Base Styles                   */
/* ============================================= */

/* Scoped to the widgets and their alert dialogs (the header dialog is moved
   to <body>, outside its container). These used to be bare `*` and `body`
   rules, which reset margins/padding and replaced the font on every element
   of the host site on any page showing a widget.
   :where() keeps the reset at zero specificity, exactly as the old `*` was,
   so every other widget rule still wins over it as before. */
:where(.weather-widget-container, .alert-modal),
:where(.weather-widget-container, .alert-modal) * {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* Fallback stack only: the selected plugin font is applied by the inline
   rule from gwpro_get_font_inline_css(), which outranks this. */
.weather-widget-container,
.alert-modal {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* ============================================= */
/* Transition Defaults                          */
/* ============================================= */

.weather-widget-header,
.weather-widget-sidebar,
.weather-widget-header *,
.weather-widget-sidebar * {
  transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;
  transition-duration: 200ms;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}

/* Disable transitions for reduced motion preference */
@media (prefers-reduced-motion: reduce) {
  .weather-widget-header,
  .weather-widget-sidebar,
  .weather-widget-header *,
  .weather-widget-sidebar * {
    transition: none !important;
    animation: none !important;
  }
}

/* ============================================= */
/* Utility Classes                              */
/* ============================================= */

/* No-select utility */
.no-select {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

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

/* Visually hidden but focusable */
.sr-only-focusable:focus,
.sr-only-focusable:active {
  position: static;
  width: auto;
  height: auto;
  padding: inherit;
  margin: inherit;
  overflow: visible;
  clip: auto;
  white-space: normal;
}

/* ============================================= */
/* Container Base Styles                        */
/* ============================================= */

.weather-widget-container {
  width: 100%;
  max-width: 100%;
}

#weather-widget-container-header,
#weather-widget-container-sidebar {
  width: 100%;
}

/* ============================================= */
/* Focus Styles for Accessibility               */
/* ============================================= */

/* Custom focus ring for interactive elements */
.weather-widget-header a:focus-visible,
.weather-widget-header button:focus-visible,
.weather-widget-sidebar a:focus-visible,
.weather-widget-sidebar button:focus-visible,
[data-role="unit-toggle"]:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* Remove default outline when using focus-visible */
.weather-widget-header a:focus:not(:focus-visible),
.weather-widget-header button:focus:not(:focus-visible),
.weather-widget-sidebar a:focus:not(:focus-visible),
.weather-widget-sidebar button:focus:not(:focus-visible) {
  outline: none;
}

/* ============================================= */
/* Skip Link for Accessibility                  */
/* ============================================= */

.gwpro-skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px 16px;
  z-index: 100;
  text-decoration: none;
  font-weight: 600;
}

.gwpro-skip-link:focus {
  top: 0;
}

/* ============================================= */
/* Bottom-right controls (buttons + alert)       */
/* ============================================= */

/* Make the tab wrapper a positioning context */
.weather-widget-header {
  position: relative;
}

/* ============================================= */
/* Print Styles                                 */
/* ============================================= */

@media print {
  .weather-widget-header,
  .weather-widget-sidebar {
    background: #fff !important;
    color: #000 !important;
    box-shadow: none !important;
    border: 1px solid #ccc !important;
  }

  .weather-widget-header::before,
  .weather-widget-sidebar::before {
    display: none !important;
  }

  .alert-icon-class,
  .forecast-toggle-controls {
    display: none !important;
  }
}
/* ============================================================================
   Font-Independent Layout Normalization
   ============================================================================
   The Typography setting now offers 18 fonts with very different metrics
   (x-heights, character widths, default leading). These rules pin down every
   dimension that a font could otherwise influence, so the widget layout stays
   identical no matter which font the user selects.
   ========================================================================= */

/* 1. Normalize optical size and vertical rhythm.
   - font-size-adjust scales every font so its x-height matches Roboto's
     (aspect ~0.52), so small-x-height serifs (EB Garamond, Playfair Display)
     don't render visually smaller than the sans-serifs at the same em size.
     Browsers without support simply ignore it.
   - An explicit unitless line-height overrides each font's own default
     leading, which otherwise varies enough to shift rows vertically. */
.weather-widget-header,
.weather-widget-sidebar {
  font-size-adjust: 0.52;
  line-height: 1.4;
  /* Tabular (fixed-width) numerals keep temperatures, times, and
     percentages the same width in every font, including proportional
     serifs, so columns don't jitter between values. */
  font-variant-numeric: tabular-nums lining-nums;
}

/* 2. Interactive controls never wrap or reflow in wide fonts.
   Playfair Display and Merriweather are ~15-20% wider than Roboto; without
   nowrap, tab labels like "Precipitation" or "UV Index" wrap to two lines
   and change the tab bar height. */
.weather-widget-header .tablinks,
.weather-widget-header .forecast-toggle-btn,
.weather-widget-header .unit-toggle-btn,
.weather-widget-sidebar .unit-toggle-btn {
  white-space: nowrap;
}

/* 3. Fixed-width forecast columns.
   The theme stylesheets give hourly cells only a min-width, so wide fonts
   grow individual columns and desynchronize the strip. Locking flex-basis
   and width makes column geometry font-independent. (Widget-class prefix
   deliberately out-specifies the equal-specificity theme rules, which load
   after this file.) */
.weather-widget-header #hourly-tabs .flex-tabcontent > div,
.weather-widget-header #seven-day-tabs .flex-tabcontent > div {
  flex: 0 0 5em;
  width: 5em;
  max-width: 5em;
  min-width: 5em;
  text-align: center;
}

/* 4. Truncate overflow inside fixed columns instead of breaking layout.
   Each cell stacks three block rows (label, icon, value); any row whose
   text exceeds the fixed column width ellipsizes. Full values remain
   available via existing title/aria-label attributes (e.g. AQI badges). */
.weather-widget-header .flex-tabcontent > div > div {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 5. Cap the weather location's line length so long addresses wrap early
   instead of pushing right-side elements out of position.
   30ch fits roughly 32 proportional characters per line (the width of
   "University of Florida, Southwest"), so e.g.
   "University of Florida, Southwest 40th Place, Gainesville, FL, US"
   renders as two-to-three short lines inside a fixed-width box. Because
   ch is font-relative, the cap tracks the selected font automatically:
   wide fonts get a wider box, monospace wider still, but always the same
   character count — so the elements to the right of the location sit in
   the same place no matter the font or the address length. The min()
   guard keeps the box from exceeding its container on narrow screens.
   (Widget-class prefix out-specifies the themes' max-width: 100% rules.) */
.weather-widget-header .weather-city,
.weather-widget-sidebar .weather-location {
  max-width: min(30ch, 100%);
  white-space: normal;
  overflow-wrap: break-word;
}

/* 6. Column discipline for the header's top row.
   The location column yields (shrinks) when space is tight; the two
   parameter columns are rigid and content-sized, and their label/value
   rows never wrap — so values like "0.23 mm" can't break onto a second
   line when a wide font eats the horizontal space. Any remaining box
   slack on the wrapped location heading is removed at runtime by
   gwproFitLocationWidth() in weatherApiAdapter.js, which pins the
   heading's width to its widest rendered line. */
.weather-widget-header .custom-flex-col1 {
  flex: 0 1 auto;
  min-width: 0;
}

.weather-widget-header .custom-flex-col2,
.weather-widget-header .custom-flex-col3 {
  flex: 0 0 auto;
}

.weather-widget-header .custom-flex-col2 > div,
.weather-widget-header .custom-flex-col3 > div {
  white-space: nowrap;
}

/* Neutral setup / failure message shown in place of widget content.
   Used when no location has been configured, or when weather data
   could not be loaded. Inherits the widget's own font and colours so it
   does not look like a broken element. */
.gwpro-setup-message {
    padding: 1.5em 1em;
    margin: 0;
    text-align: center;
    font-size: 0.95rem;
    line-height: 1.5;
    opacity: 0.85;
}

/* ============================================================================
   Phone Layout (<= 600px)
   ============================================================================
   The header widget was previously removed on phones by a userAgent test in
   headerWidget.js. It now renders everywhere, so this block reflows the
   desktop three-column layout into a single-column card.

   Two things made the widget unusable at phone width before:

   1. The 7-day strip has no .scroll-container (unlike the hourly strip), and
      main-styles pins every forecast column to a fixed 5em. Seven columns plus
      gaps is ~41em / 656px, which forced horizontal scrolling on the whole
      PAGE, not just the strip.
   2. .forecast-toggle-row and .alert-container are absolutely positioned
      against the article with right/bottom offsets sized for a wide card, so
      at phone width they landed on top of the forecast content.

   All selectors are prefixed with .weather-widget-header so they out-specify
   the single-class rules in gwpro-dark-theme.css / gwpro-light-theme.css,
   which are injected after this stylesheet. Nothing here applies above 600px.
   ========================================================================= */

/* The disclosure control exists in the markup at every width but is only ever
   shown on phones. */
.gwpro-mobile-expand-row {
  display: none;
}

/* Category tab strips: one row at every width.
   The theme stylesheets let the eight tabs wrap, and this file only switched
   to a single row below 600px. From 601px up, and in any narrow content
   column on a desktop, the strip broke onto a second or third row, often
   leaving AQI alone on the last one. Wrapping depends on the widget's width,
   not the screen's, so no viewport breakpoint can prevent it; one scrollable
   row can. Where all eight tabs fit, nothing scrolls and nothing changes.

   justify-content MUST be flex-start. Both theme stylesheets set
   `.tab { justify-content: center }` inside their own max-width:900px block,
   which is harmless while the tabs wrap, but breaks a horizontal scroll
   container: centred content overflows equally in both directions, and the
   part that overflows past the container's left edge sits at a negative
   offset that scrollLeft cannot reach (it is clamped at 0). The end of the
   strip stays reachable, so the symptom is one-sided - you can swipe to the
   last tab but cannot swipe back to the first.

   (Widget-class prefix out-specifies the theme stylesheets' `.tab` and
   `.tablinks` rules, which load after this file.) */
.weather-widget-header .tab {
  flex-wrap: nowrap;
  justify-content: flex-start;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* A scroll container clips anything outside its padding box, which would
     cut off the 4px focus ring (2px offset + 2px outline) on every tab.
     4px of padding gives the ring room; the matching negative margins keep
     the tabs exactly where they sat before. */
  padding: 4px;
  scroll-padding-inline: 4px;
  margin: calc(1em - 4px) -4px calc(0.5em - 4px);
}

.weather-widget-header .tab::-webkit-scrollbar {
  display: none;
}

/* Tabs keep their natural width instead of shrinking and clipping labels. */
.weather-widget-header .tablinks {
  flex: 0 0 auto;
  scroll-snap-align: start;
}

/* Slim scrollbar for mouse users only.
   Touch screens swipe, trackpads scroll sideways and keyboard focus scrolls
   each tab into view, so the scrollbar stays hidden for those. A plain mouse
   wheel cannot scroll sideways, so without a visible bar the tabs past the
   edge (often AQI) were unreachable for mouse users. The bar only appears
   when the row actually overflows, and uses the active theme's colours.
   Firefox and Chrome/Edge 121+ use scrollbar-width/-color; Safari and older
   Chrome use the ::-webkit-scrollbar rules (Chrome ignores those once the
   standard properties are set). */
@media (hover: hover) and (pointer: fine) {
  .weather-widget-header .tab {
    scrollbar-width: thin;
    scrollbar-color: var(--gwpro-text-muted, #94a3b8) transparent;
  }

  .weather-widget-header .tab::-webkit-scrollbar {
    display: block;
    height: 6px;
  }

  .weather-widget-header .tab::-webkit-scrollbar-track {
    background: transparent;
  }

  .weather-widget-header .tab::-webkit-scrollbar-thumb {
    background: var(--gwpro-text-muted, #94a3b8);
    border-radius: 3px;
  }
}

@media (max-width: 600px) {
  /* --- Card shell ------------------------------------------------------- */

  /* Flex column so the alert notice can be pulled above the fold with order,
     independent of its position at the end of the markup. */
  .weather-widget-header {
    display: flex;
    flex-direction: column;
    padding: 0.875em;
    margin: 0.5em 0;
  }

  .weather-widget-header .flex-row1 { order: 1; }
  .weather-widget-header .alert-container { order: 2; }
  .weather-widget-header .gwpro-mobile-expand-row { order: 3; }
  .weather-widget-header #seven-day-tabs { order: 4; }
  .weather-widget-header #hourly-tabs { order: 5; }

  /* --- Current conditions ---------------------------------------------- */

  /* The 900px breakpoint turns every .flex-row into a column, which also
     stacks the icon, temperature and unit toggle. Keep that hero row
     horizontal - it is the widget's signature element. */
  .weather-widget-header .custom-row {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5em;
  }

  .weather-widget-header .weather-city {
    font-size: 1.25em;
  }

  /* --- Parameter columns ------------------------------------------------ */

  /* The two parameter columns (rain chance, gusts, UV, sunrise, low /
     precipitation, visibility, humidity, sunset, high) are hidden outright on
     phones rather than reflowed. Ten label/value pairs is a lot of dense text
     on a small screen, and all but two of those figures are also present in
     the forecast strips, which are the better place to read them.

     The exceptions are sunrise and sunset: there is no forecast tab for
     either, so hiding these columns removes both from the phone layout
     entirely. If they need to come back, the place for them is the summary
     card above, not a re-expanded column.

     This is unconditional at phone width - it is not tied to the collapsed
     state, so the disclosure control reveals the forecast only. */
  .weather-widget-header .custom-flex-col2,
  .weather-widget-header .custom-flex-col3 {
    display: none;
  }

  /* --- Tab strips ------------------------------------------------------- */

  /* Eight category tabs wrap into four rows at phone width. One swipeable row
     with snap points keeps the control compact and the card height stable.

     justify-content MUST be flex-start here. Both theme stylesheets set
     `.tab { justify-content: center }` inside their own max-width:900px block,
     which is harmless while the tabs wrap, but breaks a horizontal scroll
     container: centred content overflows equally in both directions, and the
     part that overflows past the container's left edge sits at a negative
     offset that scrollLeft cannot reach (it is clamped at 0). The end of the
     strip stays reachable, so the symptom is one-sided - you can swipe to the
     last tab but cannot swipe back to the first. */
  /* The single swipeable row itself is set for every width further up
     ("Category tab strips"); only the phone sizing lives here. */
  .weather-widget-header .tab {
    margin: calc(0.75em - 4px) -4px calc(0.5em - 4px);
  }

  /* 2.75em against a 0.85em font is ~44px: the minimum comfortable touch
     target (WCAG 2.5.8 asks for 24px, platform guidance for 44px). */
  .weather-widget-header .tablinks {
    display: inline-flex;
    align-items: center;
    min-height: 2.75em;
    padding: 0.5em 0.9em;
    font-size: 0.85em;
  }

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

  /* Give the 7-day strip the horizontal scroll the hourly strip already has,
     so seven fixed-width columns can no longer overflow the page. */
  .weather-widget-header #seven-day-tabs .tabcontent,
  .weather-widget-header #hourly-tabs .scroll-container {
    overflow-x: auto;
    max-width: 100%;
    -webkit-overflow-scrolling: touch;
  }

  /* 4.5em columns fit four-and-a-bit per screen at 360px, which reads as
     "there is more to swipe" rather than as a clipped column. */
  .weather-widget-header #hourly-tabs .flex-tabcontent > div,
  .weather-widget-header #seven-day-tabs .flex-tabcontent > div {
    flex: 0 0 4.5em;
    width: 4.5em;
    min-width: 4.5em;
    max-width: 4.5em;
  }

  /* Same reasoning as .tab above: a centred flex row inside a horizontal
     scroll container loses its leading items. */
  .weather-widget-header .flex-tabcontent {
    justify-content: flex-start;
    gap: 0.5em;
  }

  /* --- Controls that were absolutely positioned ------------------------- */

  .weather-widget-header .forecast-toggle-row,
  .weather-widget-header .alert-container {
    position: static;
    right: auto;
    bottom: auto;
    justify-content: flex-start;
    padding: 0;
    margin: 0.25em 0;
  }

  .weather-widget-header .forecast-toggle-btn {
    min-height: 2.5em;
  }

  /* --- Disclosure control ---------------------------------------------- */

  .weather-widget-header .gwpro-mobile-expand-row {
    display: block;
    margin: 0.75em 0 0.25em 0;
  }

  /* currentColor and transparent rather than theme variables, so the control
     inherits whichever palette (dark or light) is active without needing a
     copy in each theme stylesheet. */
  .weather-widget-header .gwpro-mobile-expand {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5em;
    width: 100%;
    min-height: 2.75em;
    padding: 0.625em 1em;
    font: inherit;
    font-size: 0.875em;
    font-weight: 600;
    color: inherit;
    background: transparent;
    border: 1px solid currentColor;
    border-radius: 0.5em;
    opacity: 0.85;
    cursor: pointer;
  }

  .weather-widget-header .gwpro-mobile-expand:hover {
    opacity: 1;
  }

  .weather-widget-header .gwpro-mobile-expand-chevron {
    display: inline-block;
    transform: rotate(180deg);
    transition: transform 200ms cubic-bezier(0.4, 0, 0.2, 1);
  }

  /* --- Collapsed state -------------------------------------------------- */

  /* toggleSevenDayHourly() sets `display` as an inline style on these two
     regions, so the collapsed state has to out-rank an inline declaration.
     This is the one place !important is load-bearing rather than cosmetic. */
  .weather-widget-header.gwpro-mobile-collapsed #seven-day-tabs,
  .weather-widget-header.gwpro-mobile-collapsed #hourly-tabs {
    display: none !important;
  }

  .weather-widget-header.gwpro-mobile-collapsed .gwpro-mobile-expand-chevron {
    transform: rotate(0deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .weather-widget-header .gwpro-mobile-expand-chevron {
    transition: none;
  }
}

/* ============================================= */
/* Condition video and pause/play (WCAG 2.2.2)   */
/* ============================================= */

/* The condition animation is a muted, looping 16:9 <video>
   (js/headerWidget.js) shown in a rounded frame beside the temperature.

     desktop        192 x 108   (12em)
     tablet <=900px 224 x 126   (14em)
     phone  <=600px full-width banner, up to 360 x 203

   The frame keeps its 16:9 shape before the poster or video arrives, so the
   row never jumps. Corner radius and shadow come from the light/dark theme
   stylesheets. */
.weather-widget-header .gwpro-condition-media {
  position: relative;
  display: block;
  flex: 0 0 auto;
  width: 12em;
  max-width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  line-height: 0;
  background: rgba(127, 127, 127, 0.18);
}

/* Same frame whether it holds the video or, for conditions without an
   animation yet, the static image. */
.weather-widget-header .gwpro-condition-media #current-condition-icon {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  margin: 0;
  object-fit: cover;
  border-radius: 0;
  filter: none;
  pointer-events: none;
}

/* Legacy animated WebPs (webp-animations/, used until a condition has a
   video) may not be 16:9, so show them whole, centred in the frame, rather
   than cropped. The frame's own background and shadow are dropped so a
   square image does not sit inside a visible widescreen box. */
/* The frame keeps the 16:9 frame's height but shrinks to the image's own
   width, so a square image keeps its proportions and the pause button sits on
   its corner. Browsers without :has() fall back to the image contained,
   uncropped, in the 16:9 frame. */
.weather-widget-header .gwpro-condition-media #current-condition-icon.gwpro-condition-animated {
  object-fit: contain;
}

.weather-widget-header .gwpro-condition-media:has(.gwpro-condition-animated) {
  --gwpro-legacy-height: 6.75em; /* 108px, the 16:9 frame's desktop height */
  width: auto;
  height: var(--gwpro-legacy-height);
  aspect-ratio: auto;
  background: transparent;
}

.weather-widget-header .gwpro-condition-media:has(.gwpro-condition-animated) #current-condition-icon {
  width: auto;
  max-width: 100%;
  height: 100%;
}

@media (max-width: 900px) {
  .weather-widget-header .gwpro-condition-media:has(.gwpro-condition-animated) {
    --gwpro-legacy-height: 7.875em; /* 126px */
  }
}

@media (max-width: 600px) {
  .weather-widget-header .gwpro-condition-media:has(.gwpro-condition-animated) {
    --gwpro-legacy-height: 10em; /* 160px */
    flex-basis: auto;
  }
}

@media (max-width: 900px) {
  /* The tablet breakpoint stacks every .flex-row into a column; keep the
     video, temperature and unit toggle side by side. */
  .weather-widget-header .custom-row {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }

  .weather-widget-header .gwpro-condition-media {
    width: 14em;
  }
}

@media (max-width: 600px) {
  /* Phones: the video becomes a banner across the summary card, with the
     temperature and unit toggle on the line below. */
  .weather-widget-header .gwpro-condition-media {
    flex-basis: 100%;
    width: 100%;
    max-width: 22.5em;
  }
}

.weather-widget-header .gwpro-motion-toggle {
  -webkit-appearance: none;
  appearance: none;
  position: absolute;
  right: 0.375em;
  bottom: 0.375em;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  padding: 0;
  margin: 0;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%;
  background: rgba(15, 23, 36, 0.72);
  color: #ffffff;
  cursor: pointer;
  opacity: 0.7;
  transition: opacity 0.15s ease;
}

.weather-widget-header .gwpro-condition-media:hover .gwpro-motion-toggle,
.weather-widget-header .gwpro-motion-toggle:focus-visible,
.weather-widget-header .gwpro-motion-toggle[aria-pressed="true"] {
  opacity: 1;
}

.weather-widget-header .gwpro-motion-toggle .gwpro-icon-play,
.weather-widget-header .gwpro-motion-toggle[aria-pressed="true"] .gwpro-icon-pause {
  display: none;
}

.weather-widget-header .gwpro-motion-toggle[aria-pressed="true"] .gwpro-icon-play {
  display: block;
}

@media (hover: none) {
  .weather-widget-header .gwpro-motion-toggle {
    opacity: 1;
  }
}

/* ============================================= */
/* Block alignment (block.json "align" support)  */
/* ============================================= */

/* The sidebar card is a fixed-width object, so when it is floated left or
   right it needs an explicit width, and centering needs auto margins. */
.gwpro-weather-block.alignleft,
.gwpro-weather-block.alignright {
  width: 100%;
  max-width: 340px;
}

.gwpro-weather-block.aligncenter {
  margin-left: auto;
  margin-right: auto;
  max-width: 340px;
}

.gwpro-weather-block.alignleft {
  margin-right: 1.5em;
}

.gwpro-weather-block.alignright {
  margin-left: 1.5em;
}
