/*
 * static/css/map.css — Styles for the interactive map page (/map/).
 *
 * Kept in a standalone stylesheet rather than @tailwindcss directives
 * because the selectors below target MapLibre internals and a custom
 * MapLibre Popup. Design tokens (colour, type) still come from base.css
 * / @theme — the locals below are MapLibre-chrome-only.
 *
 * SNOW-35 removed the #frame phone-mock wrapper; the page now extends
 * public/base.html and the map fills the viewport minus the site nav.
 * SNOW-36 reintroduces search + save-offline as a floating utility
 * cluster pinned top-right (.map-utility-*). The legend selector is
 * retained for SNOW-38. SNOW-174 replaced the bottom-sheet drawer with
 * a MapLibre Popup (.region-popup / .region-tooltip-*).
 */

:root {
    --paper: #f4f1e8;
    --ink: #1a1a1a;
    --muted: #5f5e5a;
    --border: rgba(0, 0, 0, 0.12);
    /* Icon / label colour painted on top of a dark filled circle (the
       scrubber play-forward and play-reverse buttons at rest). Kept as a
       named token so the inversion stays consistent if --ink ever shifts. */
    --on-ink: #ffffff;
    --serif: Georgia, "Times New Roman", serif;
    --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
}

/* ——————————————————————————————————————————————————————————————
   Floating utility cluster (SNOW-36)
   Two frosted-glass pills pinned top-right: a search pill that
   expands in-place to reveal the existing combobox input, and a
   round "save offline" icon button. Safe-area insets respected so
   the pills never sit under the iOS notch / Dynamic Island.
   ——————————————————————————————————————————————————————————————*/

.map-utility-cluster {
    position: absolute;
    top: calc(env(safe-area-inset-top, 0px) + 12px);
    right: calc(env(safe-area-inset-right, 0px) + 12px);
    z-index: 4;
    display: flex;
    align-items: flex-start;
    gap: 8px;
}

.map-utility-pill {
    display: inline-flex;
    align-items: center;
    height: 40px;
    background: var(--color-glass);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    border: 0.5px solid var(--color-border);
    border-radius: 999px;
    box-shadow: var(--shadow-glass);
    color: var(--color-text-1);
    padding: 0;
}

/* SNOW-79: ``.map-utility-pill--button`` (the round 40×40 "Save
   offline" icon button + its saving/saved/error data-state variants
   and the spin keyframe) was removed when the precache feature
   retired. No active call sites remain in the template. If a future
   ticket reintroduces an icon-only utility pill, recreate the rule
   then rather than carrying it as dead CSS. */

/* Basemap layer picker (SNOW-58) — round 40×40 pill that anchors a
   popover of basemap radio options. ``position: relative`` so the
   absolutely-positioned ``.basemap-menu`` tracks the pill rather than
   the cluster, which keeps the popover under the pill even after the
   search pill expands and shifts the layout. */
.map-utility-pill--basemap {
    position: relative;
    width: 40px;
    flex: 0 0 auto;
    justify-content: center;
}

.map-utility-pill--basemap:hover {
    filter: brightness(1.04);
}

.basemap-menu {
    position: absolute;
    top: 48px;
    right: 0;
    margin: 0;
    padding: 4px;
    list-style: none;
    min-width: 148px;
    background: var(--color-card);
    border: 0.5px solid var(--color-border);
    border-radius: 12px;
    box-shadow: var(--shadow-glass);
    z-index: 5;
}

.basemap-menu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 12px;
    background: transparent;
    border: 0;
    border-radius: 8px;
    color: var(--color-text-1);
    font: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
}

.basemap-menu-item::before {
    content: "";
    display: inline-block;
    width: 14px;
    height: 14px;
    flex: 0 0 auto;
    border: 1.5px solid var(--color-border);
    border-radius: 50%;
    background: transparent;
    transition: background 120ms ease, border-color 120ms ease;
}

.basemap-menu-item[aria-checked="true"]::before {
    background: var(--color-text-1);
    border-color: var(--color-text-1);
    box-shadow: inset 0 0 0 2.5px var(--color-card);
}

.basemap-menu-item:hover {
    background: rgba(0, 0, 0, 0.04);
}

.basemap-menu-item:focus-visible {
    outline: 2px solid var(--color-text-1);
    outline-offset: 2px;
}

/* SNOW-59: overlay section appended to the basemap popover. The
   separator + section label divide overlay checkboxes from the
   basemap radios above; checkbox glyphs are square rather than the
   round radio dot so the role distinction reads at a glance. */
.basemap-menu-separator {
    height: 1px;
    margin: 6px 8px;
    background: var(--color-border);
}

.basemap-menu-section-label {
    padding: 4px 12px 2px;
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-2, var(--color-text-1));
    pointer-events: none;
}

.basemap-menu-item--overlay::before {
    border-radius: 3px;
}

.basemap-menu-item--overlay[aria-checked="true"]::before {
    background: var(--color-text-1);
    border-color: var(--color-text-1);
    box-shadow: inset 0 0 0 2px var(--color-card);
}

/* Disabled overlay (Micro regions — required, can't be toggled). The
   tick still reads as "on" but the row signals it isn't actionable:
   not-allowed cursor, dimmed text, no hover highlight. */
.basemap-menu-item[disabled],
.basemap-menu-item[aria-disabled="true"] {
    color: var(--color-text-2, var(--color-text-1));
    opacity: 0.65;
    cursor: not-allowed;
}

.basemap-menu-item[disabled]:hover,
.basemap-menu-item[aria-disabled="true"]:hover {
    background: transparent;
}

/* Search pill — collapsed to a round 40×40 by default; on expansion
   grows to reveal the input beside the icon. */
.map-utility-pill--search {
    width: 40px;
    flex: 0 0 auto;
    overflow: hidden;
    transition: width 180ms cubic-bezier(0.32, 0.72, 0, 1);
}

.map-utility-pill--search[data-state="expanded"] {
    width: min(calc(100vw - 76px), 280px);
}

/* Transparent icon button inside the search pill — also the standalone
   click target when the pill is collapsed. */
.map-utility-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    color: inherit;
    cursor: pointer;
}

.map-utility-button:focus-visible {
    outline: 2px solid var(--color-text-1);
    outline-offset: 2px;
    border-radius: 999px;
}

/* Search input inside the expanded pill — hidden until the pill is
   in the expanded state. Width/opacity transition in sync with the
   pill's width transition so the reveal feels like one motion. */
.map-utility-pill--search .search-input {
    flex: 1 1 auto;
    min-width: 0;
    width: 0;
    height: 40px;
    padding: 0;
    margin: 0;
    background: transparent;
    border: 0;
    outline: 0;
    font: inherit;
    font-size: 14px;
    color: var(--color-text-1);
    opacity: 0;
    pointer-events: none;
    transition: opacity 120ms ease 60ms;
}

.map-utility-pill--search[data-state="expanded"] .search-input {
    width: auto;
    padding: 0 14px 0 2px;
    opacity: 1;
    pointer-events: auto;
}

.map-utility-pill--search .search-input::placeholder {
    color: var(--color-text-3);
}

/* Suppress the native clear-button "x" so the pill styling stays uniform. */
.map-utility-pill--search .search-input::-webkit-search-cancel-button,
.map-utility-pill--search .search-input::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
}

/* Search-results dropdown — anchored below the cluster, right-aligned
   to it. Width caps at 320px on wide viewports and shrinks to fit
   narrow ones. Sits on top of everything that isn't the bottom sheet. */
.search-results {
    position: absolute;
    top: 48px;
    right: 0;
    width: min(calc(100vw - 24px), 320px);
    margin: 0;
    padding: 0;
    list-style: none;
    background: var(--color-card);
    border: 0.5px solid var(--color-border);
    border-radius: 12px;
    box-shadow: var(--shadow-glass);
    max-height: 320px;
    overflow-y: auto;
    z-index: 5;
}

.search-result {
    padding: 10px 12px;
    cursor: pointer;
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 10px;
    border-bottom: 0.5px solid var(--border);
}

.search-result:last-child {
    border-bottom: 0;
}

.search-result:hover,
.search-result.active {
    background: #f2efe7;
}

.search-result-text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.search-result-primary {
    font-size: 13px;
    color: var(--ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.search-result-secondary {
    font-size: 11px;
    color: var(--muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.search-result-badge {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 11px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-weight: 500;
    color: var(--muted);
    background: #ece8dc;
    padding: 2px 7px;
    border-radius: 10px;
}

/* Country flag inside the search result badge. Width is set per country
   because inline SVG without explicit dimensions defaults to 300×150;
   the square CH flag uses its 1:1 ratio and the 3:2 AT/FR/IT flags all
   share a width. A hairline border keeps white-bordered flags legible
   on the badge's beige background. */
.search-result-flag {
    flex: 0 0 auto;
    height: 9px;
    border: 0.5px solid rgba(0, 0, 0, 0.15);
    border-radius: 1px;
}

.search-result-flag--ch {
    width: 9px;
}

.search-result-flag--at,
.search-result-flag--fr,
.search-result-flag--it {
    width: 13px;
}

.search-empty {
    padding: 12px;
    text-align: center;
    font-size: 12px;
    color: var(--muted);
}

/* Full-viewport map pages (/ and /map/) override the default body class so
   the body is sized to 100dvh rather than Tailwind's `min-h-screen`
   (100vh). On mobile, 100vh measures the *large* viewport — it ignores the
   browser address bar — so a 100vh flex column overshoots the visible area
   and pushes the bottom-pinned season scrubber and the in-flow site footer
   below the fold. 100dvh (the dynamic viewport height) tracks the visible
   area, so nav + map + footer all fit. On desktop the two units are equal,
   so this is a no-op there. The column stays `flex flex-col`, so #map's
   `flex: 1 1 auto` still fills the space between the nav and the footer. */
.map-fullscreen {
    min-height: 100dvh;
}

#map {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    position: relative;
}

.hint {
    padding: 10px 12px;
    font-size: 11px;
    color: var(--muted);
    text-align: center;
    border-top: 0.5px solid var(--border);
}

/* Collapsible map-info panel (SNOW-38, redesigned SNOW-230) — top-left
   overlay holding the danger-scale legend, the active tile attribution,
   and the SLF data licence. Single (i) entry point so map chrome stays
   uncluttered. The card is absolutely positioned relative to the toggle
   and opens to the right so it never collides with the scrubber.
   Stacking: scrubber=2, legend=3, utility cluster=4. */

.map-legend {
    position: absolute;
    left: calc(env(safe-area-inset-left, 0px) + 12px);
    top: calc(env(safe-area-inset-top, 0px) + 12px);
    z-index: 3;
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Date pill — floats above the scrubber thumb and slides horizontally
   as the user drags or the timelapse advances. Anchored inside
   .season-scrubber-track so the --thumb-pct percentage is track-relative.
   Server-rendered for first-paint correctness; map.js updates both the
   --thumb-pct custom property and the text content on every
   snowdesk:date-changed / snowdesk:date-preview event. */
.map-date-pill {
    position: absolute;
    bottom: 100%;
    left: var(--thumb-pct, 50%);
    transform: translateX(-50%);
    /* Lift the pill above the entire scrubber container, not just the 3px
       track. The scrubber pill is ~43px tall with the track at its
       vertical centre (20px from the top), so a 22px margin-bottom pushes
       the pill 2px clear of the scrubber's top edge. */
    margin-bottom: 22px;
    height: 28px;
    padding: 0 10px;
    display: inline-flex;
    align-items: center;
    background: var(--color-glass);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    border: 0.5px solid var(--color-border);
    border-radius: 999px;
    box-shadow: var(--shadow-glass);
    color: var(--color-text-1);
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    white-space: nowrap;
    user-select: none;
    pointer-events: none;
    z-index: 1;
}

.map-legend-toggle {
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: var(--color-glass);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    border: 0.5px solid var(--color-border);
    border-radius: 999px;
    box-shadow: var(--shadow-glass);
    color: var(--color-text-1);
    cursor: pointer;
}

.map-legend-card {
    position: absolute;
    /* Anchor to the right of the (i) toggle, top-aligned with it. */
    left: 40px;              /* 32px button + 8px gap */
    top: 0;
    min-width: 200px;
    max-width: 260px;
    padding: 10px 12px;
    background: var(--color-glass);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    border: 0.5px solid var(--color-border);
    border-radius: 8px;
    box-shadow: var(--shadow-glass);
    font-size: 11px;
    line-height: 1.5;
    color: var(--color-text-1);
    transform-origin: top left;
    opacity: 0;
    transform: translateX(-4px) scale(0.98);
    pointer-events: none;
    transition: opacity 160ms ease-out, transform 160ms ease-out;
}

/* Hairline divider between the three sections of the info card so the
   legend, map attribution and bulletin attribution read as separate
   groups without needing extra chrome. */
.map-legend-section + .map-legend-section {
    border-top: 0.5px solid var(--color-border);
    margin-top: 8px;
    padding-top: 8px;
}

/* Attribution text styling — smaller and more muted than the legend rows
   so the legend remains the primary read in the card. */
.map-legend-attribution {
    margin: 0;
    font-size: 10px;
    line-height: 1.4;
    color: var(--color-text-2);
}

.map-legend-attribution-link {
    color: inherit;
    text-decoration: underline;
}

.map-legend-attribution-link:hover {
    color: var(--color-text-1);
}

.map-legend[data-state="expanded"] .map-legend-card {
    opacity: 1;
    transform: none;
    pointer-events: auto;
}

.map-legend-title {
    font-weight: 500;
    color: var(--color-text-2);
    margin-bottom: 4px;
}

.map-legend-row {
    display: flex;
    align-items: center;
    gap: 6px;
}

.map-legend-swatch {
    width: 10px;
    height: 10px;
    display: inline-block;
    border-radius: 2px;
    border: 0.5px solid rgba(0, 0, 0, 0.15);
}

.map-legend-swatch--low          { background: var(--color-eaws-low); }
.map-legend-swatch--moderate     { background: var(--color-eaws-moderate); }
.map-legend-swatch--considerable { background: var(--color-eaws-considerable); }
.map-legend-swatch--high         { background: var(--color-eaws-high); }

/* SNOW-78: legend pin matches the on-map resort circle paint — neutral
 * dark fill with a thin white stroke so it reads against any basemap or
 * EAWS rating fill. Smaller than the rating swatches so the pin looks
 * like a point of interest rather than a coloured area. */
.map-legend-pin {
    width: 8px;
    height: 8px;
    display: inline-block;
    border-radius: 50%;
    background: #1a1a1a;
    border: 1px solid #ffffff;
    box-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.25);
}

.maplibregl-ctrl-attrib {
    font-size: 9px !important;
}

/* SNOW-79: ``.offline-cta`` (the "Save offline" full-width CTA that
   sat below the search field) was retired with the rest of the
   precache feature. Removed wholesale — no remaining call sites.
   SNOW-174: bottom-sheet drawer (.sheet, .region-peek-*, .region-expanded-*)
   replaced by a MapLibre Popup — see .region-popup / .region-tooltip-*
   below. */

/* MapLibre Popup brand overrides (SNOW-174) — applied via className:
 * "region-popup" on the Popup constructor. The default MapLibre popup
 * chrome is replaced with the same frosted-glass card used by the
 * utility cluster; the close button inherits the brand ink colour. */

.region-popup .maplibregl-popup-content {
    padding: 14px 16px;
    border-radius: 12px;
    /* More translucent than --color-glass so the choropleth shows
     * through; blur is bumped to keep text legible against the busy
     * map background. */
    background: rgba(248, 246, 240, 0.65);
    -webkit-backdrop-filter: blur(14px);
    backdrop-filter: blur(14px);
    border: 2px solid var(--color-border, rgba(0, 0, 0, 0.12));
    box-shadow: var(--shadow-glass, 0 4px 16px rgba(0, 0, 0, 0.12));
    color: var(--color-text-1, #1a1a1a);
    font-family: var(--sans);
    /* Constrain width; the maxWidth on the Popup constructor is the outer
     * bound — this prevents the content from touching the tip. */
    min-width: 200px;
}

.region-popup[data-level="low"]          .maplibregl-popup-content { border-color: var(--color-eaws-low); }
.region-popup[data-level="moderate"]     .maplibregl-popup-content { border-color: var(--color-eaws-moderate); }
.region-popup[data-level="considerable"] .maplibregl-popup-content { border-color: var(--color-eaws-considerable); }
.region-popup[data-level="high"]         .maplibregl-popup-content { border-color: var(--color-eaws-high); }
.region-popup[data-level="very_high"]    .maplibregl-popup-content { border-color: var(--color-eaws-very-high); }

.dark .region-popup .maplibregl-popup-content {
    /* Same translucency story in dark mode — the popup is more
     * transparent than other glass surfaces by design. */
    background: rgba(20, 22, 26, 0.6);
}

.region-popup .maplibregl-popup-close-button {
    font-size: 18px;
    line-height: 1;
    color: var(--color-text-2, #5f5e5a);
    padding: 4px 8px;
    border-radius: 4px;
}

.region-popup .maplibregl-popup-close-button:hover {
    background: rgba(0, 0, 0, 0.06);
    color: var(--color-text-1, #1a1a1a);
}

/* Region tooltip content — the server-rendered HTML injected by
 * region_summary() into popup.setHTML(). Structural region metadata:
 * inline chip + name header row, geographic breadcrumb, date caption,
 * and bulletin CTA (SNOW-174). */

.region-tooltip {
    display: flex;
    flex-direction: column;
    gap: 6px;
    /* Pad right so the name doesn't run under MapLibre's close button. */
    padding-right: 24px;
}

/* Header row: danger-tile chip vertically centred against the region name. */
.region-tooltip-header {
    display: flex;
    align-items: center;
    gap: 10px;
}

.region-tooltip-name {
    font-family: var(--serif);
    font-size: 17px;
    font-weight: 500;
    line-height: 1.2;
    margin: 0;
    color: var(--color-text-1, #1a1a1a);
}

.region-tooltip-breadcrumb {
    margin: 0;
    font-size: 11px;
    line-height: 1.5;
    color: var(--color-text-2, #5f5e5a);
}

/* Bulletin CTA — styled as a lightweight secondary button. */
.region-tooltip-bulletin-link {
    display: inline-block;
    margin-top: 8px;
    padding: 6px 12px;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 500;
    text-decoration: none;
    color: var(--color-text-1, #1a1a1a);
    background: var(--color-bg-2, rgba(0, 0, 0, 0.05));
    border: 1px solid var(--color-border, rgba(0, 0, 0, 0.1));
}

.region-tooltip-bulletin-link:hover {
    background: var(--color-bg-3, rgba(0, 0, 0, 0.1));
}

/* Default icon shown in place of the danger-tile when no bulletin exists. */
.region-tooltip-icon-default {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    opacity: 0.45;
}

/* Muted label shown in place of the bulletin CTA when no bulletin exists. */
.region-tooltip-no-bulletin {
    margin-top: 8px;
    padding: 6px 0;
    font-size: 13px;
    font-style: italic;
    color: var(--color-text-2, #5f5e5a);
}

/* Placeholder for future editorial content — empty by default. */
.region-tooltip-editorial {
    margin-top: 4px;
}

/* Season scrubber — floating bottom-pinned pill (SNOW-37 / SNOW-230).
   Attribution was relocated to top-right so the scrubber now sits flush
   at the bottom edge above the safe-area inset. */

.season-scrubber,
.season-scrubber-demo {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px;
    background: rgba(255, 255, 255, 0.75);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border: 0.5px solid var(--border);
    border-radius: 999px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    user-select: none;
}

/* On the map page, the scrubber is pinned over the MapLibre viewport. */
.season-scrubber {
    position: absolute;
    left: 12px;
    right: 12px;
    bottom: calc(5px + env(safe-area-inset-bottom, 0px));
    z-index: 2;
}

/* On the component-library page, the demo pill flows in normal document
   order and sits on the parchment surface rather than a map. */
.season-scrubber-demo {
    position: relative;
    margin: 8px 0;
}

.season-scrubber-track {
    flex: 1 1 auto;
    height: 3px;
    background: rgba(0, 0, 0, 0.08);
    border-radius: 2px;
    position: relative;
    /* overflow: visible so the date pill (absolutely positioned above the
       track) is not clipped by the track height. */
    overflow: visible;
    cursor: grab;
    transition: height 160ms cubic-bezier(0.32, 0.72, 0, 1);
}

/* SNOW-314: when a region's season is painted into the track, it grows from
   the thin grey rail into the full ribbon. The thumb rides over the colours;
   the track itself still owns drag/click-to-scrub. */
.season-scrubber-track[data-ribbon="on"] {
    height: 14px;
    border-radius: 7px;
}

@media (prefers-reduced-motion: reduce) {
    .season-scrubber-track { transition: none; }
}

/* Decorative season-ribbon fill inside the track. One flex cell per day,
   no pointer events (the track beneath handles scrubbing), clipped to the
   track's rounded rail. */
.scrubber-ribbon {
    position: absolute;
    inset: 0;
    display: flex;
    border-radius: inherit;
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
}

.scrubber-ribbon-cell {
    flex: 1 1 0;
    min-width: 0;
    height: 100%;
}

/* Month-boundary hairline (SNOW-314). At mobile density each day cell is
   sub-pixel, so per-day gaps are impossible; instead a thin overlay marks the
   first-of-month cells (~6 across the season) for orientation. Drawn as an
   absolutely-positioned pseudo-element so it adds no width — the cells stay
   aligned 1:1 with the scrubber thumb. */
.scrubber-ribbon-cell--month {
    position: relative;
}

.scrubber-ribbon-cell--month::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    width: 1px;
    background: rgba(0, 0, 0, 0.4);
    pointer-events: none;
}

.season-scrubber-thumb {
    position: absolute;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--ink);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    touch-action: none;
    /* Ride over the decorative ribbon fill. */
    z-index: 2;
}

.season-scrubber-track.dragging {
    cursor: grabbing;
}

.season-scrubber-track.animating .season-scrubber-thumb {
    transition: left 200ms cubic-bezier(0.32, 0.72, 0, 1);
}

/* Shared geometry for every transport button on the scrubber — play,
   skip-to-start, play-reverse, play-forward, skip-to-end. Each button is
   a circular flex-centred target with no padding or margin; the per-variant
   rules below add size, fill, and stroke. SVG state-swap (play icon when
   stopped, stop icon when playing) is shared across the play-reverse and
   play-forward variants. */
.scrubber-transport-button {
    flex: 0 0 auto;
    margin: 0;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    cursor: pointer;
}

.scrubber-transport-button[data-state="playing"] .scrubber-play-icon,
.scrubber-transport-button[data-state="stopped"] .scrubber-stop-icon {
    display: none;
}

/* Play-reverse and play-forward transport buttons — 22×22 dark-filled
   circles that act as a symmetric pair flanking the track. The filled
   dark fill picks them out as the primary actions. SVG state is swapped
   via the data-state attribute set by static/js/map.js. */
.scrubber-play,
.scrubber-reverse {
    width: 22px;
    height: 22px;
    background: var(--ink);
    color: var(--on-ink);
    border: none;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}

.scrubber-play:hover,
.scrubber-reverse:hover {
    background: #000;
}

/* Skip-to-start / skip-to-end transport buttons — same shared geometry
   as .scrubber-play but 22×22 so the play button remains the visual
   anchor. Colour inherits from the scrubber context (dark text on the
   frosted pill) rather than the inverted play-button style. */
.scrubber-skip {
    width: 22px;
    height: 22px;
    background: transparent;
    color: var(--ink);
    border: 0.5px solid var(--border);
}

.scrubber-skip:hover {
    background: rgba(0, 0, 0, 0.06);
}


/* Season scrubber loading state (SNOW-234).
   While the season-ratings fetch is in flight the scrubber carries
   data-state="loading". Transport buttons and the track are hidden via
   display:none so pointer events are naturally suppressed until the data
   arrives. The pill retains its full left:12px / right:12px footprint so
   there is no layout reflow when the state switches to "ready".
   The -demo variant mirrors the live widget class for the component library
   demo wrapper, which uses class="season-scrubber-demo" instead of
   class="season-scrubber". */
.season-scrubber[data-state="loading"] .scrubber-transport-button,
.season-scrubber-demo[data-state="loading"] .scrubber-transport-button {
    display: none;
}

.season-scrubber[data-state="loading"] .season-scrubber-track,
.season-scrubber-demo[data-state="loading"] .season-scrubber-track {
    display: none;
}

/* Once the fetch resolves successfully, the loading placeholder is hidden.
   Error state intentionally does NOT hide the placeholder — the JS error
   path writes "Season data unavailable" into the element, so it must stay
   visible. Controls are hidden in error state by the rule below. */
.season-scrubber[data-state="ready"] .season-scrubber-loading,
.season-scrubber-demo[data-state="ready"] .season-scrubber-loading {
    display: none;
}

/* In error state the controls are hidden (no data to scrub) but the
   loading/error placeholder remains visible so the user sees the message. */
.season-scrubber[data-state="error"] .scrubber-transport-button,
.season-scrubber-demo[data-state="error"] .scrubber-transport-button,
.season-scrubber[data-state="error"] .season-scrubber-track,
.season-scrubber-demo[data-state="error"] .season-scrubber-track {
    display: none;
}

/* Loading / error placeholder text — centred single-line label that sits
   inside the existing pill flex container. Inherits the pill's monospace
   font stack and matches the muted label colour used elsewhere on the
   scrubber (the date pill uses --ink; the placeholder is secondary copy). */
.season-scrubber-loading {
    flex: 1 1 auto;
    text-align: center;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    color: var(--muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* —————————————————————————————————————————————————————————
   SNOW-314 — Season ribbon
   A compact horizontal strip of coloured day cells docked above the
   season scrubber. One cell per calendar day, coloured by peak danger
   rating for the selected region. Clicking a cell dispatches
   snowdesk:scrub-to to drive the scrubber and recolour the choropleth.
   ————————————————————————————————————————————————————————— */

/* The ribbon is a sibling of #season-scrubber inside #map (which is
   position:relative via MapLibre). It sits above the scrubber pill:
   the scrubber's bottom edge is 5px + safe-area from the viewport bottom,
   the pill itself is ~40px tall, and the ribbon header + track add ~36px.
   Using a fixed bottom offset keeps the ribbon visually anchored above the
   scrubber without depending on scrubber height in CSS. */
.season-ribbon {
    position: absolute;
    bottom: calc(54px + env(safe-area-inset-bottom, 0px));
    left: 12px;
    right: 12px;
    z-index: 2;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.ribbon-header {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 0 2px;
}


/* SNOW-314: persistent focused-region readout — names the region whose season
   fills the scrubber track and shows its danger for the scrubbed day. Survives
   playback (cache-fed by map.js); the source of truth for "which region", with
   the map popup demoted to on-tap detail. */
.region-readout[hidden] {
    display: none;
}

.region-readout {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    /* Frosted pill so the label stays legible over the map (it was getting
       lost against the choropleth). Matches the scrubber / utility-pill idiom. */
    padding: 4px 10px;
    background: rgba(255, 255, 255, 0.75);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    border: 0.5px solid var(--border);
    border-radius: 999px;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
    /* When a region is focused the pill is an <a> to the bulletin. */
    text-decoration: none;
    color: var(--ink);
    transition: box-shadow 120ms ease, background 120ms ease;
}

/* Focused → the whole pill is the bulletin CTA: pressable, with a hover lift
   that signals clickability. */
.region-readout.has-region {
    cursor: pointer;
}

.region-readout.has-region:hover,
.region-readout.has-region:focus-visible {
    background: rgba(255, 255, 255, 0.95);
    box-shadow: 0 3px 16px rgba(0, 0, 0, 0.16);
}

@media (prefers-reduced-motion: reduce) {
    .region-readout {
        transition: none;
    }
}

.region-readout-name {
    font-weight: 600;
    color: var(--ink);
}

/* The action affordance — "View bulletin →", set off by a divider so it reads
   as the tappable part of the pill. Shown only when a region is focused. */
.region-readout-cta {
    font-weight: 600;
    color: var(--ink);
    padding-left: 8px;
    border-left: 0.5px solid var(--border);
}

.region-readout.has-region:hover .region-readout-cta {
    text-decoration: underline;
}

/* No region focused → date-only: drop the (empty) name, the danger swatch,
   and the CTA so the chip reads as a plain date. */
.region-readout:not(.has-region) .region-readout-name,
.region-readout:not(.has-region) .region-readout-cta {
    display: none;
}

.region-readout:not(.has-region) .region-readout-danger::before {
    display: none;
}

/* Danger label carries a leading colour swatch via a pseudo-element; the
   swatch colour is set inline by map.js from the EAWS rating token. */
.region-readout-danger {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--muted);
}

.region-readout-danger::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 2px;
    background: var(--readout-swatch, transparent);
    box-shadow: inset 0 0 0 0.5px var(--border);
}

/* EAWS rating fills for the .scrubber-ribbon-cell elements that paint
   the season-scrubber track when a region is focused (SNOW-314).
   Use the same CSS custom properties as the legend swatches and the
   MapLibre choropleth fill layer. */
.ribbon-cell--no_rating   { background: rgba(0, 0, 0, 0.08); }
.ribbon-cell--low         { background: var(--color-eaws-low); }
.ribbon-cell--moderate    { background: var(--color-eaws-moderate); }
.ribbon-cell--considerable { background: var(--color-eaws-considerable); }
.ribbon-cell--high        { background: var(--color-eaws-high); }
.ribbon-cell--very_high   { background: var(--color-eaws-very-high); }

/* —————————————————————————————————————————————————————————
   SNOW-314 — Homepage intro overlay (#home-intro)
   Absolutely positioned over #map; rendered with show_intro=True from
   the home() view. Dismissed via button or Escape key; restored by
   visiting /#about. home_intro.js owns the state machine.
   ————————————————————————————————————————————————————————— */

.home-intro {
    position: absolute;
    /* Offset from safe areas so the card clears the status bar / notch. */
    top: calc(env(safe-area-inset-top, 0px) + 64px);
    left: calc(env(safe-area-inset-left, 0px) + 16px);
    z-index: 5;
    /* Pointer events on the card only; the map behind the card stays interactive. */
    pointer-events: none;
}

.home-intro[hidden] {
    display: none;
}

.home-intro-card {
    pointer-events: auto;
    background: var(--color-glass);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border: 0.5px solid var(--color-border);
    box-shadow: var(--shadow-glass);
    border-radius: 12px;
    padding: 20px 22px;
    max-width: 320px;
    color: var(--color-text-1);
    font-family: var(--sans);
}

.home-intro-identity {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
}

.home-intro-wordmark {
    font-size: 18px;
    font-weight: 600;
    letter-spacing: -0.02em;
    color: var(--color-text-1);
}

.home-intro-tagline {
    font-size: 13px;
    line-height: 1.5;
    color: var(--color-text-2);
    margin: 0 0 12px;
}

/* Off-season reference line inside the intro card — rendered only when
   is_offseason is True; points at the persistent #map-offseason-note pill. */
.home-intro-offseason-ref {
    font-size: 11px;
    line-height: 1.4;
    color: var(--color-text-3);
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    margin: 0 0 12px;
    padding: 6px 8px;
    background: rgba(0, 0, 0, 0.04);
    border-radius: 6px;
}

.home-intro-actions {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.home-intro-sample-link {
    font-size: 13px;
    color: var(--color-text-2);
    text-decoration: none;
    line-height: 1.4;
}

.home-intro-sample-link:hover {
    color: var(--color-text-1);
    text-decoration: underline;
}

.home-intro-dismiss {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 8px 16px;
    border-radius: 999px;
    background: var(--ink);
    color: var(--on-ink);
    font-size: 13px;
    font-weight: 500;
    border: none;
    cursor: pointer;
    font-family: var(--sans);
    transition: opacity 120ms ease;
}

.home-intro-dismiss:hover {
    opacity: 0.85;
}

.home-intro--no-motion .home-intro-dismiss {
    transition: none;
}

/* Dark mode: the glass card uses the dark glass token automatically via
   the .dark body class set by the theme head partial. */
.dark .home-intro-card {
    background: var(--color-glass);
    color: var(--color-text-1);
}
