body {
    background: var(--bg-body);
    color: var(--text-primary);
    min-height: 100vh;
    font-family: var(--font-body);
    transition: background-color 0.3s ease, color 0.3s ease;
}

.country-flag {
    max-width: 50px;
    max-height: 20px;
    border-radius: 3px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.3);
}

.image-contain {
    object-fit: contain;
    object-position: center;
    max-width: 100%;
    max-height: 100%;
    border-radius: 5px;
}

/* --- Sticky news ticker at the bottom --- */
#news-ticker {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 40px;
    background: linear-gradient(90deg, var(--primary-dark), var(--primary-color), var(--primary-dark));
    background-size: 200% 100%;
    color: var(--on-primary);
    overflow: hidden;
    white-space: nowrap;
    display: flex;
    align-items: center;
    box-shadow: 0 -4px 15px rgba(0,0,0,0.4);
    z-index: 9999;
    animation: gradientShift 5s ease infinite;
}

#news-ticker-content {
    display: inline-block;
    will-change: transform;
    padding-left: 100%;
    animation: ticker 25s linear infinite;
    font-size: 15px;
    line-height: 40px;
}

#news-ticker-content a {
    color: var(--on-primary);
    text-decoration: none;
    margin-right: 50px;
    transition: color 0.3s;
}

#news-ticker-content a:hover {
    color: var(--accent-color);
}

@keyframes ticker {
    0% { transform: translateX(0); }
    100% { transform: translateX(-100%); }
}

@keyframes gradientShift {
    0%, 100% { background-position: 0% 50%; }
    50% { background-position: 100% 50%; }
}

#news-ticker:hover #news-ticker-content {
    animation-play-state: paused;
}


/* --- Weather panel (moved out of inline styles) --- */
#weather-display {
    margin-bottom: 10px;
    padding: 20px;
    background: linear-gradient(135deg, var(--weather-from), var(--weather-to));
    border-radius: 12px;
    border: 2px solid var(--primary-color);
    box-shadow: var(--shadow-md);
}

.weather-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 15px;
}

.weather-icon {
    flex: 1;
    display: block;
    font-size: 4rem;
    text-align: center;
}

.weather-detail {
    flex: 2;
    text-align: left;
}

.weather-temp {
    font-size: 2rem;
    font-weight: bold;
    color: var(--primary-color);
    line-height: 1;
}

.weather-desc {
    margin-top: 8px;
    font-size: 1.1rem;
    color: var(--text-secondary);
    font-weight: 500;
}

.weather-wind {
    margin-top: 8px;
    font-size: 0.95rem;
    color: var(--text-muted);
}

/* --- Air quality, inset under the weather row in the same card --- */

.aq-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border-color);
}

.aq-badge {
    flex-shrink: 0;
    min-width: 44px;
    padding: 6px 4px;
    border-radius: 8px;
    text-align: center;
    font-size: 1.15rem;
    font-weight: bold;
    /* The band colours below are fixed brand colours from the European AQI scale, so the
       text on them is pinned too rather than following the theme. */
    text-shadow: none;
}

.aq-detail {
    min-width: 0;
}

.aq-label {
    padding-top: 0;
    font-size: 0.95rem;
    font-weight: 500;
    color: var(--text-secondary);
}

.aq-pollutants {
    padding-top: 4px;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* Official European AQI band colours (EEA). */
.aq-good        { background: #50f0e6; color: #14342f; }
.aq-fair        { background: #50ccaa; color: #10302a; }
.aq-moderate    { background: #f0e641; color: #3a3600; }
.aq-poor        { background: #ff5050; color: #ffffff; }
.aq-very-poor   { background: #960032; color: #ffffff; }
.aq-extreme     { background: #7d2181; color: #ffffff; }

/* --- ISS live position (frame 5) --- */

#iss-display {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
}

/* The globe and its buttons side by side, both centred in the panel. */
.globe-stage {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 18px;
}

.globe-jump {
    display: flex;
    flex-direction: column;
    gap: 10px;
    flex-shrink: 0;
}

.jump-btn {
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--primary-color);
    border-radius: 10px;
    background: var(--bg-card);
    color: var(--primary-color);
    cursor: pointer;
    box-shadow: var(--shadow-sm);
    transition: background 0.2s ease, color 0.2s ease, transform 0.2s ease;
}

.jump-btn:hover:not(:disabled) {
    background: linear-gradient(145deg, var(--primary-color), var(--primary-dark));
    color: var(--on-primary);
    transform: scale(1.08);
}

.jump-btn:focus-visible {
    outline: 3px solid var(--highlight-color);
    outline-offset: 2px;
}

.jump-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

/* Square, and sized in px rather than em so the four icons match despite coming from two
   different source grids. */
.ic-jump {
    width: 20px;
    height: 20px;
}

/* Visible to a screen reader, not on screen - the buttons carry only an icon. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.globe-wrap {
    position: relative;
    width: 100%;
    max-width: 450px;
}

/* Below the panel's comfortable width the column lies down under the globe instead of
   squeezing it. */
@media (max-width: 700px) {
    .globe-stage {
        flex-direction: column;
    }

    .globe-jump {
        flex-direction: row;
    }
}

@media (prefers-reduced-motion: reduce) {
    .jump-btn:hover:not(:disabled) {
        transform: none;
    }
}

#iss-globe {
    display: block;
    width: 100%;
    /* Square by construction, so the globe never becomes an ellipse in a narrow panel. */
    aspect-ratio: 1;
    margin-bottom: 4px;
    cursor: grab;
    /* A drag must spin the globe, not select the page or pan it on a phone. */
    touch-action: none;
    user-select: none;
}

#iss-globe.is-dragging {
    cursor: grabbing;
}

.globe-ocean,
.globe-graticule,
.globe-land,
.globe-rim {
    pointer-events: none;
}

.globe-ocean {
    fill: var(--map-ocean-to);
}

.globe-graticule {
    fill: none;
    stroke: var(--primary-color);
    stroke-width: 0.4;
    opacity: 0.35;
}

.globe-land {
    fill: var(--globe-land-fill);
    stroke: var(--primary-dark);
    stroke-width: 0.9;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.globe-rim {
    fill: none;
    stroke: var(--primary-color);
    stroke-width: 1.5;
}

/* The visitor, when their own location is known and on the near face.
   Deliberately not --accent-color: that is the same value as --map-ocean-to, so the
   marker was invisible against the sea it sits on. White reads on both themes. */
.globe-viewer {
    fill: #ffffff;
    stroke: var(--primary-dark);
    stroke-width: 1;
}

.globe-iss {
    fill: var(--highlight-color);
    stroke: #ffffff;
    stroke-width: 1;
}

.globe-iss-halo {
    fill: var(--highlight-color);
    opacity: 0.25;
}

/* Recent earthquakes. Semi-transparent so overlapping ones along a fault line read as a
   denser cluster rather than a single blob. */
.globe-quake {
    fill: var(--quake);
    opacity: 0.7;
}

.globe-night {
    fill: var(--globe-night);
    /* The shading is decoration over the map; let hover reach the markers beneath. */
    pointer-events: none;
}

.globe-sun {
    fill: var(--globe-sun);
    stroke: var(--primary-dark);
    stroke-width: 0.6;
}

.legend-sun {
    background: var(--globe-sun);
    border: 1px solid var(--primary-dark);
}

.legend-visitor {
    background: var(--spike);
}

.legend-moon {
    background: var(--globe-moon);
    border: 1px solid var(--primary-dark);
}

.legend-plate {
    background: var(--globe-plate);
}

.legend-aurora {
    background: var(--globe-aurora);
}

/* --- Extra globe layers --- */

.globe-moon {
    fill: var(--globe-moon);
    stroke: var(--primary-dark);
    stroke-width: 0.6;
}

/* All three are outlines over the map, and none should catch the pointer during a drag. */
.globe-plate,
.globe-track,
.globe-link {
    fill: none;
    pointer-events: none;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.globe-plate {
    stroke: var(--globe-plate);
    stroke-width: 0.8;
    opacity: 0.75;
}

.globe-track {
    stroke: var(--globe-track);
    stroke-width: 1.1;
    opacity: 0.85;
}

/* Dashed, so it reads as a sight line rather than as something physically there. */
.globe-link {
    stroke: var(--globe-link);
    stroke-width: 1;
    stroke-dasharray: 3 3;
    opacity: 0.9;
}

.globe-aurora {
    fill: var(--globe-aurora);
    opacity: 0.5;
    pointer-events: none;
}

/* While the aurora feed is on its way. */
.legend-toggle.is-loading {
    opacity: 0.6;
    cursor: progress;
}

/* Visitor spikes. Not interactive - they would otherwise be one more thing for a drag
   starting on the globe to land on. */
.globe-spike {
    stroke: var(--spike);
    stroke-width: 1.4;
    stroke-linecap: round;
    pointer-events: none;
}

.globe-spike-tip {
    fill: var(--spike);
    pointer-events: none;
}

/* --- Legend entries double as layer switches --- */

.legend-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 2px 4px;
    border: none;
    border-radius: 5px;
    background: none;
    color: inherit;
    font: inherit;
    cursor: pointer;
    transition: opacity 0.15s ease, background 0.15s ease;
}

.legend-toggle:hover {
    background: var(--border-color);
}

/* Off: dimmed, with the swatch hollowed out so the state reads without relying on the
   colour alone. */
.legend-toggle[aria-pressed="false"] {
    opacity: 0.45;
}

.legend-toggle[aria-pressed="false"] .legend-dot {
    background: transparent;
    box-shadow: inset 0 0 0 1.5px currentColor;
}

/* Key to the globe's markers. Wraps rather than overflowing when the panel is narrow. */
.globe-legend {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px 14px;
    margin-top: 8px;
    padding-bottom: 4px;
    list-style: none;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.globe-legend li {
    display: flex;
    align-items: center;
    gap: 6px;
}

.legend-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* Each swatch matches the marker it stands for - see .globe-iss, .globe-viewer and
   .globe-quake above. */
.legend-iss {
    background: var(--highlight-color);
}

.legend-viewer {
    background: #ffffff;
    border: 1px solid var(--primary-dark);
}

.legend-quake {
    background: var(--quake);
}

/* Section heading inside a panel - used by the holidays list. */
.panel-subhead {
    padding-top: 0;
    font-size: 0.78rem;
    font-weight: bold;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-muted);
}

/* --- Sunrise and sunset --- */

.sun-row {
    display: flex;
    gap: 10px;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border-color);
}

.sun-item {
    display: flex;
    flex: 1;
    align-items: center;
    gap: 8px;
    min-width: 0;
}

/* Same reason as .moon-icon: these files carry no fill of their own. */
.sun-icon {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    fill: var(--primary-color);
}

.sun-label {
    padding-top: 0;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.sun-time {
    padding-top: 2px;
    font-size: 1rem;
    font-weight: bold;
    color: var(--text-secondary);
}

.sun-daylight {
    padding-top: 8px;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* --- Moon phase, third row of the weather card --- */

.moon-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border-color);
}

/* The icons ship with no fill, so they paint black by default. Inlined (see moon.js)
   they inherit this instead and follow the theme. */
.moon-icon {
    flex-shrink: 0;
    width: 42px;
    height: 42px;
    fill: var(--primary-color);
}

.moon-name {
    padding-top: 0;
    font-size: 0.95rem;
    font-weight: 500;
    color: var(--text-secondary);
}

.moon-meta {
    padding-top: 4px;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* --- Upcoming holidays, at the foot of the panel --- */

#holidays-display {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--border-color);
}

#holiday_list {
    margin-top: 6px;
    list-style: none;
}

#holiday_list li {
    display: flex;
    gap: 10px;
    padding-top: 6px;
    font-size: 0.88rem;
    color: var(--text-primary);
    text-shadow: var(--text-emboss);
}

.holiday-date {
    flex-shrink: 0;
    min-width: 3.6rem;
    font-weight: bold;
    color: var(--primary-color);
}

.holiday-name {
    min-width: 0;
}

/* Shown when a panel's data could not be loaded */
.field-error {
    text-align: center;
    color: var(--text-muted);
}

/* --- Map tooltip (moved out of inline styles) --- */
/* The duplicated ticker track that produces a seamless loop */
.ticker-clone {
    display: inline-block;
    will-change: transform;
    padding-left: 100%;
    animation: ticker 25s linear infinite;
    font-size: 15px;
    line-height: 40px;
}

.ticker-clone a {
    color: var(--on-primary);
    text-decoration: none;
    margin-right: 50px;
}

#news-ticker:hover .ticker-clone {
    animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
    #news-ticker-content,
    .ticker-clone,
    #news-ticker {
        animation: none;
    }
}

/* --- Theme toggle -------------------------------------------------------- */

/* The sprite itself must never render or take up space. */
.sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

/* An inline <svg> is not sized like an <img>: width:auto resolves to 100% of the
   container rather than to the viewBox ratio, so both axes are set explicitly. */
.icon {
    fill: currentColor;
    vertical-align: -0.125em;
}

.ic-moon { width: 0.821em; height: 0.857em; }
.ic-sun  { width: 0.953em; height: 0.999em; }

.theme-toggle {
    position: fixed;
    /* Clears the 40px news ticker pinned to the bottom of the viewport. */
    bottom: 56px;
    right: 2rem;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--shadow-lg);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    z-index: 10000;
    color: var(--on-primary);
    font-size: 1.5rem;
}

.theme-toggle:hover {
    transform: scale(1.1) rotate(15deg);
    box-shadow: var(--shadow-xl);
}

.theme-toggle:focus-visible {
    outline: 3px solid var(--highlight-color);
    outline-offset: 3px;
}

.icon-sun { display: none; }
[data-theme="dark"] .icon-moon { display: none; }
[data-theme="dark"] .icon-sun { display: block; }

@media (prefers-reduced-motion: reduce) {
    .theme-toggle {
        transition: none;
    }
    .theme-toggle:hover {
        transform: none;
    }
}
