@charset "UTF-8";

/* ==========================================================================
   1. FONTS
   Rubik variable font from @fontsource-variable/rubik 5.2.8 (SIL OFL 1.1,
   see ../fonts/OFL.txt). latin-ext is only fetched when a page needs it.
   ========================================================================== */

@font-face {
    font-family: 'Rubik';
    font-style: normal;
    font-display: swap;
    font-weight: 300 900;
    src: url("../fonts/rubik-latin-wght-normal.b65daadded74.woff2") format("woff2-variations"),
         url("../fonts/rubik-latin-wght-normal.b65daadded74.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Rubik';
    font-style: normal;
    font-display: swap;
    font-weight: 300 900;
    src: url("../fonts/rubik-latin-ext-wght-normal.15c3dca723cb.woff2") format("woff2-variations"),
         url("../fonts/rubik-latin-ext-wght-normal.15c3dca723cb.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ==========================================================================
   2. DESIGN TOKENS
   base.html sets <html data-bs-theme> from prefers-color-scheme before the
   first paint. The chart backgroundColor in charts.js must match --lw-surface.
   ========================================================================== */

:root {
    --lw-bg: #f3f4f6;
    --lw-surface: #ffffff;
    --lw-surface-2: #eef0f3;
    --lw-surface-3: #e2e5ea;
    --lw-border: rgba(16, 24, 40, 0.08);
    --lw-border-strong: rgba(16, 24, 40, 0.16);
    --lw-text: #1f2328;
    --lw-text-muted: #5f6670;
    /* Accent as a fill (header, active buttons) and as text on a surface */
    --lw-accent: #3949ab;
    --lw-accent-hover: #303f9f;
    --lw-on-accent: #ffffff;
    --lw-accent-text: #3949ab;
    /* Min and max: the charts' blue and red, darkened to 4.5:1 on white */
    --lw-min: #2366c2;
    --lw-max: #c42f2e;
    --lw-ok: #2e9d57;
    --lw-warn: #f0a400;
    --lw-bad: #d93025;
    --lw-radius: 0.75rem;
    --lw-gap: 0.75rem;
    --lw-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 2px 6px rgba(16, 24, 40, 0.05);
    /* Tonal buttons: the accent as a tint */
    --lw-accent-soft: #e8eaf6;
    --lw-accent-soft-hover: #d6daf0;
    /* Header: indigo in light mode */
    --lw-header-bg: #3949ab;
    --lw-header-border: transparent;
    --lw-header-text: #ffffff;
    --lw-header-text-muted: rgba(255, 255, 255, 0.82);
    --lw-header-active-bg: rgba(255, 255, 255, 0.16);
    --lw-header-active-line: transparent;
    /* Night bands on the day and week charts; -clear is the same colour at
       zero alpha for the dusk and dawn fades */
    --lw-night-band: rgba(40, 50, 110, 0.06);
    --lw-night-band-clear: rgba(40, 50, 110, 0);

    --bs-primary: #3949ab;
    --bs-primary-rgb: 57, 73, 171;
    --bs-link-color: #3949ab;
    --bs-link-color-rgb: 57, 73, 171;
    --bs-link-hover-color: #283593;
    --bs-link-hover-color-rgb: 40, 53, 147;
}

[data-bs-theme=dark] {
    --lw-bg: #141518;
    --lw-surface: #1e2024;
    --lw-surface-2: #272a30;
    --lw-surface-3: #31353c;
    --lw-border: rgba(255, 255, 255, 0.08);
    --lw-border-strong: rgba(255, 255, 255, 0.16);
    --lw-text: #e3e5e8;
    --lw-text-muted: #9aa1ab;
    --lw-accent: #3f51b5;
    --lw-accent-hover: #4a5cc4;
    --lw-accent-text: #9fa8da;
    /* The charts' dark-palette blue and red */
    --lw-min: #6da7ec;
    --lw-max: #f08080;
    --lw-shadow: none;
    --lw-accent-soft: rgba(159, 168, 218, 0.14);
    --lw-accent-soft-hover: rgba(159, 168, 218, 0.22);
    /* Header: the dark surface; the active link is underlined instead of filled */
    --lw-header-bg: var(--lw-surface);
    --lw-header-border: var(--lw-border);
    --lw-header-text: var(--lw-text);
    --lw-header-text-muted: var(--lw-text-muted);
    --lw-header-active-bg: transparent;
    --lw-header-active-line: var(--lw-accent-text);
    --lw-night-band: rgba(0, 0, 0, 0.25);
    --lw-night-band-clear: rgba(0, 0, 0, 0);

    --bs-primary: #9fa8da;
    --bs-primary-rgb: 159, 168, 218;
    --bs-link-color: #9fa8da;
    --bs-link-color-rgb: 159, 168, 218;
    --bs-link-hover-color: #c5cae9;
    --bs-link-hover-color-rgb: 197, 202, 233;
}

/* Bootstrap's components take their background from --bs-body-bg, so that
   is the card surface; the page itself is painted with --lw-bg on body */
:root,
[data-bs-theme=dark] {
    --bs-body-bg: var(--lw-surface);
    --bs-body-color: var(--lw-text);
    --bs-emphasis-color: var(--lw-text);
    --bs-secondary-color: var(--lw-text-muted);
    --bs-secondary-bg: var(--lw-surface-2);
    --bs-tertiary-bg: var(--lw-surface-2);
    --bs-border-color: var(--lw-border-strong);
    --bs-border-color-translucent: var(--lw-border);
}

/* ==========================================================================
   3. BASE / GLOBAL
   ========================================================================== */

body {
    font-family: "Rubik", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
    font-weight: 400;
    background-color: var(--lw-bg);
    color: var(--lw-text);
    -webkit-tap-highlight-color: transparent;
    overflow-x: hidden;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    margin: 0;
}

h1, h2, h3, h4, h5, h6 {
    font-weight: 400;
}

strong {
    font-weight: 500;
}

a {
    text-decoration: none;
    cursor: pointer;
    transition: color 0.2s ease-in-out;
}

a:not([href]):not([tabindex]),
a:not([href]):not([tabindex]):focus,
a:not([href]):not([tabindex]):hover {
    color: inherit;
    text-decoration: none;
}

.disabled,
:disabled {
    pointer-events: none !important;
}

.font-small {
    font-size: 0.85rem;
}

/* Bootstrap draws the thumb in its compiled primary blue */
.form-range::-webkit-slider-thumb {
    background-color: var(--lw-accent);
}

.form-range::-webkit-slider-thumb:active {
    background-color: var(--lw-accent-hover);
}

.form-range::-moz-range-thumb {
    background-color: var(--lw-accent);
}

.form-range::-moz-range-thumb:active {
    background-color: var(--lw-accent-hover);
}

/* Inline SVG icons from the {% icon %} tag (display/icons.py) */
.icon {
    display: inline-block;
    flex-shrink: 0;
    fill: currentColor;
    vertical-align: -0.125em;
}

/* Tempus Dominus prev/next arrows (unsized <svg><use> from {% icon_sprite %}) */
.tempus-dominus-widget .calendar-header svg {
    width: 0.625em;
    height: 1em;
    fill: currentColor;
    vertical-align: -0.125em;
}

/* ==========================================================================
   4. COLORS (only classes actually used)
   ========================================================================== */

.indigo {
    background-color: var(--lw-accent);
}

.blue-text {
    color: var(--lw-accent-text);
}

.red-text {
    color: var(--lw-max);
}

.white-text {
    color: var(--lw-on-accent);
}

.white-ic {
    color: var(--lw-on-accent);
}

.rgba-white-slight,
.rgba-white-slight:after {
    background-color: rgba(255, 255, 255, 0.1);
}

/* ==========================================================================
   5. TYPOGRAPHY
   ========================================================================== */

/* Card titles that are links (blog), and the larger ones of the blog */
.card-heading a {
    color: inherit;
}

.card-heading a:hover {
    color: var(--lw-accent-text);
}

.card .card-body .card-title-lg {
    font-size: 1.25rem;
    line-height: 1.3;
}

.card .card-body h1.card-title-lg {
    font-size: 1.75rem;
}

/* ==========================================================================
   6. VIEW / OVERLAY (blog image overlays)
   ========================================================================== */

.view {
    position: relative;
    overflow: hidden;
    cursor: default;
}

.view .mask {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 100%;
    overflow: hidden;
    background-attachment: fixed;
}

.view img, .view video {
    position: relative;
    display: block;
}

.overlay .mask {
    opacity: 0;
    transition: all 0.4s ease-in-out;
}

.overlay .mask:hover {
    opacity: 1;
}

/* ==========================================================================
   7. MAP
   ========================================================================== */

/* Standort: the climate text and the map stacked on the left, the longer
   station text beside them; one column on a phone */
.location-grid {
    display: grid;
    gap: 1rem;
    align-items: start;
    grid-template-areas: "climate" "station" "map";
}

.location-climate { grid-area: climate; }
.location-station { grid-area: station; }
.location-map { grid-area: map; }

@media (width >= 768px) {
    .location-grid {
        grid-template-columns: 1fr 1fr;
        grid-template-areas: "climate station" "map station";
    }
}

#osm-map {
    height: 300px;
}

.leaflet-popup-content {
    font-family: 'Rubik', sans-serif;
    font-size: 14px;
    line-height: 1.5;
}

.popup-image {
    width: 100%;
    height: auto;
    margin-top: 6px;
    border-radius: .25rem;
}

/* ==========================================================================
   8. CARDS AND GRID
   ========================================================================== */

/* One spacing step between the cards and around the page edge */
.container-fluid {
    --bs-gutter-x: calc(2 * var(--lw-gap));
}

.temprow,
.graphrow {
    --bs-gutter-x: var(--lw-gap);
    margin-top: var(--lw-gap) !important;
    margin-bottom: 0 !important;
}

/* !important to win over the mb-4 utility on the columns */
.temprow > *,
.graphrow > * {
    margin-top: 0 !important;
    margin-bottom: var(--lw-gap) !important;
}

/* An empty full-width item that ends a row early (sun and moon on a phone) */
.temprow > .row-break {
    margin-bottom: 0 !important;
}

/* The cards of one row end level */
.temprow > * > .card {
    height: 100%;
}

.card {
    --bs-card-bg: var(--lw-surface);
    --bs-card-border-width: 0;
    --bs-card-border-radius: var(--lw-radius);
    --bs-card-inner-border-radius: var(--lw-radius);
    --bs-card-spacer-y: 0.75rem;
    --bs-card-spacer-x: 0.875rem;
    font-weight: 400;
    border: 1px solid var(--lw-border);
    box-shadow: var(--lw-shadow);
}

.card .card-body h1, .card .card-body h2, .card .card-body h3,
.card .card-body h4, .card .card-body h5, .card .card-body h6 {
    font-weight: 400;
}

/* The title of every card, the chart cards included */
.card .card-body .card-heading {
    font-size: 1rem;
    font-weight: 500;
    line-height: 1.25;
    color: var(--lw-text);
    margin-bottom: 0.25rem;
}

.card .card-body .card-text {
    font-size: 0.9rem;
    font-weight: 400;
    color: var(--lw-text-muted);
}

.card-body .richtext-image {
    max-width: 100%;
    height: auto;
    display: block;
    margin: 0 auto;
}

/* ==========================================================================
   9. WEATHER DATA DISPLAY
   ========================================================================== */

/* A measurement card: min | current | max, with equally wide sides so the
   current value stays centred. Stacks when the card is too narrow (container
   query). Period pages use .obs-grid-even. */
.card-body:has(> .obs-grid) {
    container-type: inline-size;
}

/* Centred over the current value; the trend arrow is out of the flow, so it
   does not pull the title off centre */
.card-body:has(> .obs-grid) > .card-heading {
    text-align: center;
}

.obs-grid {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    grid-template-areas: "lo cur hi";
    align-items: center;
    column-gap: 0.5rem;
    row-gap: 0.125rem;
}

/* Past periods: three equal columns, labels and values level */
.obs-grid.obs-grid-even {
    grid-template-columns: 1fr 1fr 1fr;
    align-items: start;
}

/* Hidden until live_updates.js writes the first payload, so the units do not
   shift when the numbers arrive */
.card[data-name]:not(.is-ready) .obs-grid {
    visibility: hidden;
}

.obs-cur {
    grid-area: cur;
    text-align: center;
}

.obs-grid .lo-text,
.obs-grid .rise-text {
    grid-area: lo;
    text-align: left;
}

.obs-grid .hi-text,
.obs-grid .set-text {
    grid-area: hi;
    text-align: right;
}

.obs-grid .lo-text,
.obs-grid .hi-text,
.obs-grid .rise-text,
.obs-grid .set-text {
    white-space: nowrap;
}

/* Stacked: max before min, last hour before 24 hours, rise before set. Period
   cards keep each label above its value. */
@container (width < 17rem) {
    .obs-grid,
    .obs-grid.obs-grid-even {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas: "cur" "hi" "lo";
        align-items: center;
    }

    .obs-grid.obs-grid-even {
        row-gap: 0.5rem;
    }

    .obs-grid.obs-grid-rain,
    .obs-grid:has(> .rise-text) {
        grid-template-areas: "cur" "lo" "hi";
    }

    .obs-grid .lo-text,
    .obs-grid .hi-text,
    .obs-grid .rise-text,
    .obs-grid .set-text {
        text-align: center;
    }

    .obs-grid:not(.obs-grid-even) > :is(.lo-text, .hi-text, .rise-text, .set-text) {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        justify-content: center;
        column-gap: 0.375rem;
    }

    .obs-grid .stat-time {
        flex-basis: 100%;
    }
}

/* Scales with the card width so three hPa values fit on a 360px phone; full
   size from a 26.5rem card on */
.obs-current {
    font-size: clamp(1.25rem, 8cqi - 0.125rem, 2rem);
    font-weight: 400;
    line-height: 1.15;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.obs-grid:not(.obs-grid-even) .stat-value {
    font-size: clamp(0.875rem, 5cqi, 1rem);
}

/* The period pages' values, all one size and weight */
.obs-grid-even .obs-current,
.obs-grid-even .stat-value {
    font-size: clamp(1.0625rem, 5.5cqi, 1.5rem);
    font-weight: 400;
    line-height: 1.15;
}

@container (width < 17rem) {
    .obs-grid .obs-current {
        font-size: clamp(1.125rem, 19cqi, 2rem);
    }

    .obs-grid:not(.obs-grid-even) .stat-value {
        font-size: 1rem;
    }

    .obs-grid-even .obs-current,
    .obs-grid-even .stat-value {
        font-size: clamp(1.0625rem, 15cqi, 1.5rem);
    }
}

/* Moon phase icon: outlined glyph on light cards, plain glyph on dark ones.
   .obs-current in the selectors to beat weather-icons.css, which loads later. */
.obs-current .moon-light,
.obs-current .moon-dark {
    margin-right: 0.3em;
    font-size: 0.8em;
}

.obs-current .moon-dark,
[data-bs-theme=dark] .obs-current .moon-light {
    display: none;
}

[data-bs-theme=dark] .obs-current .moon-dark {
    display: inline-block;
}

.lo-text .stat-label {
    color: var(--lw-min);
}

.hi-text .stat-label {
    color: var(--lw-max);
}

.stat-label {
    font-size: 0.75rem;
    font-weight: 500;
    line-height: 1.2;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--lw-text-muted);
    margin-bottom: 0;
}

.stat-value {
    font-size: 1rem;
    font-weight: 400;
    line-height: 1.3;
    font-variant-numeric: tabular-nums;
}

.stat-time {
    font-size: 0.8125rem;
    color: var(--lw-text-muted);
    line-height: 1.3;
    font-variant-numeric: tabular-nums;
}

/* Reserve the line for the time live_updates.js fills in, to avoid layout
   shift. In a stacked tile it gets its own line: an empty box in the row
   has no baseline and would make the row taller. */
.obs-grid .stat-time {
    min-height: 1.3em;
}

/* A value carried over from an earlier record */
.obs-value.stale {
    opacity: 0.6;
    border-bottom: 1px dotted currentColor;
    cursor: help;
}

/* Out of the flow so the title does not reflow when the arrow changes */
.obs-trend {
    position: absolute;
    margin-left: 0.3em;
    color: var(--lw-text-muted);
}

/* Sized before the data arrives to avoid layout shift; 400px is the Highcharts
   default */
.chart-container {
    width: 100%;
    height: 400px;
    margin-top: 0.5rem;
}

.chart-title {
    margin-bottom: 0;
}

.chart-title a {
    color: inherit;
    text-decoration: none;
}

/* Digits of equal width, so axis ticks and tooltip rows line up */
.chart-container .highcharts-axis-labels text,
.highcharts-tooltip text {
    font-variant-numeric: tabular-nums;
}

/* Reserves the height of the table loaded after the page (--rows from the
   template). A reload keeps the previous table, dimmed. */
.table-skeleton {
    height: calc(var(--rows, 6) * (2.55rem + 1px) + 1rem);
    border-radius: calc(var(--lw-radius) / 2);
    background: linear-gradient(90deg, var(--lw-surface-2) 25%, var(--lw-surface-3) 50%, var(--lw-surface-2) 75%);
    background-size: 200% 100%;
    animation: skeleton-shimmer 1.4s ease-in-out infinite;
}

@keyframes skeleton-shimmer {
    from { background-position: 100% 0; }
    to { background-position: -100% 0; }
}

@media (prefers-reduced-motion: reduce) {
    .table-skeleton {
        animation: none;
    }
}

.archive-table-container[aria-busy="true"] table {
    opacity: 0.5;
    transition: opacity 0.2s ease-in-out;
}

/* An observation title with an explanation: a button styled as heading text */
.obs-explained {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    color: inherit;
    text-align: inherit;
    white-space: normal;
    vertical-align: baseline;
    text-decoration: underline dotted;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.22em;
    /* Fallback for browsers without color-mix() */
    text-decoration-color: currentColor;
    text-decoration-color: color-mix(in srgb, currentColor 55%, transparent);
    transition: text-decoration-color 0.15s ease-in-out;
}

/* Overrides the pointer cursor from Bootstrap's reboot */
button.obs-explained:not(:disabled) {
    cursor: help;
}

.obs-explained:hover,
.obs-explained:focus-visible {
    text-decoration-color: currentColor;
}

.obs-explained:focus-visible {
    outline: 2px solid currentColor;
    outline-offset: 3px;
    border-radius: 2px;
}

/* Readable multi-sentence body, wider than the Bootstrap default 276px */
.popover {
    --bs-popover-max-width: 320px;
    --bs-popover-body-font-size: 0.875rem;
    --bs-popover-header-font-size: 0.9rem;
}

/* ==========================================================================
   10. HEADER
   ========================================================================== */

.site-header {
    background-color: var(--lw-header-bg);
    border-bottom: 1px solid var(--lw-header-border);
    color: var(--lw-header-text);
    padding: 0.5rem 1rem;
}

.site-header .navbar-brand {
    color: var(--lw-header-text);
    font-size: 1.125rem;
    line-height: 1.3;
}

.site-header .navbar-brand strong {
    font-weight: 500;
}

.site-header .navbar-brand .font-small {
    color: var(--lw-header-text-muted);
}

.navbar-logo {
    height: 3rem;
    width: auto;
    margin-right: 0.75rem;
}

@media (width >= 992px) {
    .site-header .navbar-brand {
        min-width: 380px;
    }
}

@media (width < 1400px) {
    .site-header .navbar-brand {
        max-width: 350px;
    }
}

.site-header .navbar-collapse {
    padding-top: 0.25rem;
}

.site-header .nav-link {
    color: var(--lw-header-text-muted);
    font-size: 1.0625rem;
    padding: 0.375rem 0.75rem;
    border-radius: 0.5rem;
    transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out;
}

.site-header .nav-link:hover,
.site-header .nav-link:focus-visible {
    color: var(--lw-header-text);
}

.site-header .nav-item.active > .nav-link {
    color: var(--lw-header-text);
    font-weight: 500;
    background-color: var(--lw-header-active-bg);
    box-shadow: inset 0 -2px 0 var(--lw-header-active-line);
}

[data-bs-theme=dark] .site-header .nav-item.active > .nav-link {
    border-radius: 0;
}

.site-header .navbar-toggler {
    border: 0;
    color: var(--lw-header-text);
}

.site-header .navbar-toggler:focus {
    box-shadow: 0 0 0 2px var(--lw-header-text-muted);
}

.site-header .navbar-toggler-icon {
    background-image: url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 32 32' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.9)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 8h24M4 16h24M4 24h24'/%3E%3C/svg%3E");
}

.site-header .dropdown-menu {
    position: absolute !important;
    margin-top: 0;
}

@media (1200px <= width < 1400px) {
    .site-header .nav-link {
        padding-left: 0.5rem;
        padding-right: 0.5rem;
    }
}

/* ==========================================================================
   11. RANGE STRIP
   ========================================================================== */

/* Below xl: the time ranges as a strip under the brand, scrolling sideways
   if they do not fit, so switching the period never needs the menu */
.range-strip {
    flex-basis: 100%;
    margin: 0.5rem -1rem -0.5rem;
    padding: 0 1rem 0.5rem;
    overflow-x: auto;
    scrollbar-width: none;
}

.range-strip::-webkit-scrollbar {
    display: none;
}

.range-strip .navbar-nav {
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 0.25rem;
}

.range-strip .nav-link {
    white-space: nowrap;
}

/* ==========================================================================
   12. TABLES
   ========================================================================== */

table th {
    font-size: 0.9rem;
    font-weight: 500;
}

table td {
    font-size: 0.9rem;
    font-weight: 400;
}

table.table thead th {
    border-top: none;
    color: var(--lw-text-muted);
}

table.table th,
table.table td {
    padding-top: 1.1rem;
    padding-bottom: 1rem;
}

table.table-sm th,
table.table-sm td {
    padding-top: 0.6rem;
    padding-bottom: 0.6rem;
}

.archive-table-container .table {
    font-variant-numeric: tabular-nums;
}

/* The year column stays in view while a wide table scrolls sideways on a
   phone; the cells already carry the table background */
.archive-table-container .table th:first-child {
    position: sticky;
    left: 0;
    z-index: 1;
}

/* ==========================================================================
   13. FOOTER
   ========================================================================== */

footer.page-footer {
    margin-top: auto;
    flex-shrink: 0;
    padding: 1rem 0;
    border-top: 1px solid var(--lw-border);
    color: var(--lw-text-muted);
    font-size: 0.875rem;
}

footer.page-footer a {
    color: var(--lw-text-muted);
}

footer.page-footer a:hover {
    color: var(--lw-text);
}

/* ==========================================================================
   14. STATUS INDICATOR
   ========================================================================== */

.status-dot {
    --dot: #9e9e9e;
    width: 0.7em;
    height: 0.7em;
    border-radius: 50%;
    background-color: var(--dot);
    display: inline-block;
    margin-left: 0.5rem;
    margin-right: 0.5rem;
    position: relative;
    transition: background-color 0.5s ease;
}

.status-dot::after {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    background-color: var(--dot);
    animation: none;
    transition: background-color 0.5s ease;
}

.status-dot.green {
    --dot: var(--lw-ok);
}

.status-dot.green::after {
    animation: pulse 2s infinite;
}

.status-dot.orange {
    --dot: var(--lw-warn);
}

.status-dot.red {
    --dot: var(--lw-bad);
}

@keyframes pulse {
    0% {
        transform: scale(1);
        opacity: 1;
    }
    100% {
        transform: scale(2);
        opacity: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .status-dot.green::after {
        animation: none;
    }
}

/* ==========================================================================
   15. WEBCAM
   ========================================================================== */

/* 16:9 like the camera, sized before the image loads, at most 500px tall */
.webcam-container {
    position: relative;
    width: 100%;
    max-width: calc(500px * 16 / 9);
    aspect-ratio: 16 / 9;
    margin: 0 auto 0.75rem;
    border-radius: calc(var(--lw-radius) - 0.25rem);
    background-color: #0e0f11;
    overflow: hidden;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #a3a9b3;
}

/* The image is the button that opens the full-screen view */
.webcam-open {
    display: block;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    background: none;
    cursor: zoom-in;
}

.webcam-open:focus-visible {
    outline: 2px solid var(--lw-accent-text);
    outline-offset: -2px;
}

.webcam-container img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
}

#webcamModal .modal-body {
    display: flex;
    flex-direction: column;
    height: 100dvh;
    overflow: hidden;
}

#webcamModal .text-center {
    flex: 1;
    min-height: 0;
    display: flex;
    align-items: center;
    justify-content: center;
}

.webcam-modal-img {
    width: 100%;
    max-height: 100%;
    object-fit: contain;
    cursor: pointer;
}

.webcam-modal-close {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    z-index: 1;
    opacity: 0.9;
}

.webcam-modal-close:hover {
    opacity: 1;
}

/* Playback toolbar: round icon buttons around the time slider */
.webcam-controls {
    display: flex;
    gap: 0.375rem;
    align-items: center;
}

.webcam-controls .weather-btn {
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    border-radius: 50%;
    flex-shrink: 0;
}

.webcam-controls .form-range {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0 0.5rem;
}

.webcam-modal-controls {
    flex-shrink: 0;
    margin: 0.5rem 0.25rem;
}

.webcam-modal-controls .weather-btn {
    color: #e8e8e8;
    background-color: rgba(255, 255, 255, 0.1);
}

.webcam-modal-controls .weather-btn:hover {
    color: #fff;
    background-color: rgba(255, 255, 255, 0.2);
}

/* The play button holds a play and a pause icon; webcam.js sets .is-playing */
.webcam-controls .icon-pause,
.webcam-controls .is-playing .icon-play {
    display: none;
}

.webcam-controls .is-playing .icon-pause {
    display: inline-block;
}

/* ==========================================================================
   16. BUTTONS
   ========================================================================== */

/* Filter chips (archive statistics, blog pages) and the webcam's icon
   buttons; the pressed one is filled with the accent */
.weather-btn-group {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
    align-items: center;
}

.weather-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.375rem;
    min-height: 2rem;
    padding: 0.3125rem 0.75rem;
    font-size: 0.875rem;
    font-weight: 500;
    line-height: 1.2;
    border: 0;
    border-radius: 999px;
    background-color: var(--lw-surface-2);
    color: var(--lw-text);
    cursor: pointer;
    white-space: nowrap;
    transition: background-color 0.15s ease-in-out, color 0.15s ease-in-out;
}

.weather-btn:hover {
    background-color: var(--lw-surface-3);
    color: var(--lw-text);
}

.weather-btn:focus-visible,
.weather-btn-search:focus-visible {
    outline: 2px solid var(--lw-accent-text);
    outline-offset: 2px;
}

.weather-btn.active,
.weather-btn.active:hover {
    background-color: var(--lw-accent);
    color: var(--lw-on-accent);
}

.weather-btn.disabled {
    background-color: transparent;
}

/* Tonal action buttons: the archive's date pickers and period arrows, the
   newsletter */
.weather-btn-search {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    min-height: 2.5rem;
    padding: 0.5rem 1rem;
    font-size: 0.9375rem;
    font-weight: 500;
    line-height: 1.25;
    border: 0;
    border-radius: 0.625rem;
    background-color: var(--lw-accent-soft);
    color: var(--lw-accent-text);
    cursor: pointer;
    white-space: nowrap;
    transition: background-color 0.15s ease-in-out;
}

.weather-btn-search:hover {
    background-color: var(--lw-accent-soft-hover);
    color: var(--lw-accent-text);
}

.archive-legacy {
    margin: 0;
    text-align: center;
    color: var(--lw-text-muted);
}

/* A row of them, e.g. the archive search */
.archive-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    justify-content: center;
}

@media (width < 576px) {
    .weather-btn-group {
        justify-content: center;
    }

    .weather-btn-search {
        padding: 0.4rem 0.8rem;
        font-size: 0.875rem;
    }
}

/* ==========================================================================
   17. WIDE SCREEN LAYOUT (FHD+)
   ========================================================================== */

@media (width >= 1660px) {
    .temprow {
        display: flex;
        width: 50%;
        margin: var(--lw-gap) 0 0 0 !important;
    }

    .graphrow {
        display: flex;
        width: 50%;
        margin: var(--lw-gap) 0 0 0 !important;
    }

    .d-flex-xxl {
        display: flex !important;
    }

    .temprow .col-xl-4 {
        flex: 0 0 50%;
        max-width: 50%;
    }
}

/* ==========================================================================
   18. ERROR PAGE
   On the 404 page a tumbleweed rolls along the footer's top border
   (script in templates/404.html)
   ========================================================================== */

/* main's bottom edge is the ground; its stacking context keeps the tumbleweed
   behind the card but in front of the footer border */
.page-not-found main {
    flex: 1 0 auto;
    position: relative;
    isolation: isolate;
}

.tumbleweed-track {
    position: absolute;
    left: 0;
    right: 0;
    /* the ball's drawn edge sits ~5px inside its box: let it touch the line */
    bottom: -5px;
    height: 9rem;
    overflow: hidden;
    pointer-events: none;
    z-index: -1;
}

/* Parked just off the left edge; the script moves this one along x, hops
   .tumbleweed-hop and spins the svg */
.tumbleweed {
    position: absolute;
    bottom: 0;
    left: -56px;
    width: 56px;
    height: 56px;
    color: #8a6a3f;
}

[data-bs-theme=dark] .tumbleweed {
    color: #c9a66b;
}

.tumbleweed-hop,
.tumbleweed svg {
    display: block;
    width: 100%;
    height: 100%;
}

.tumbleweed-shadow {
    position: absolute;
    left: 20%;
    right: 20%;
    bottom: 2px;
    height: 6px;
    border-radius: 50%;
    background-color: rgba(0, 0, 0, 0.12);
}

[data-bs-theme=dark] .tumbleweed-shadow {
    background-color: rgba(0, 0, 0, 0.45);
}

@media (prefers-reduced-motion: reduce) {
    .tumbleweed-track {
        display: none;
    }
}
