/*
 * 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;
}

/* PROTOTYPE (homepage rework): bottom-right control stack — layers + locate
   pills in the conventional map-control corner, stacked vertically above the
   report roundel (which sits at bottom:60px). 108px clears the 40px report
   pill plus an 8px gap. */
.map-controls-br {
    position: absolute;
    right: calc(env(safe-area-inset-right, 0px) + 12px);
    bottom: calc(env(safe-area-inset-bottom, 0px) + 108px);
    z-index: 4;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    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);
}

/* SNOW-328: Locate-me roundel — same geometry as the basemap pill: a
   40×40 flex-centred circle that anchors the #locate-toggle button. No
   popover needed; the pill is purely an icon button. */
.map-utility-pill--locate {
    width: 40px;
    flex: 0 0 auto;
    justify-content: center;
}

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

/* Hide the MapLibre GeolocateControl's own rendered control — our
   #locate-toggle pill is the visible affordance. Hiding only the button left
   the empty .maplibregl-ctrl-group wrapper (a white box with a shadow) visible
   as a ghost in the top-right corner; it was previously masked by the utility
   cluster but is exposed once that no longer covers the corner. Hide the whole
   group — the control still works, it's triggered programmatically from the
   pill, not via this button. The button rule stays as a :has() fallback. */
.maplibregl-ctrl-geolocate {
    display: none;
}

.maplibregl-ctrl-group:has(.maplibregl-ctrl-geolocate) {
    display: none;
}

.basemap-menu {
    position: absolute;
    /* PROTOTYPE: the basemap pill lives in the bottom-right stack, so the menu
       opens to the LEFT of the roundel column and is bottom-anchored —
       mirroring the info panel, which opens to the right of the bottom-left
       (i). right:48px clears the 40px pill + 8px gap. bottom:-96px drops the
       menu's lower edge down past the locate pill (40px) + gap (8px) + the
       report-roundel offset so it lines up with the legend/report baseline
       (bottom:60px) — the safe-area inset cancels out — giving the menu the
       full screen height to grow into. */
    right: 48px;
    bottom: -96px;
    margin: 0;
    padding: 4px;
    list-style: none;
    min-width: 148px;
    /* Anchored at the bottom baseline, the menu grows upward over the full
       viewport; cap its height so the top never clips, leaving a top margin. */
    max-height: calc(100dvh - 96px);
    overflow-y: auto;
    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;
    /* SNOW-328: keep multi-word labels (e.g. "Bulletin groupings") on a
       single line. The menu is shrink-to-fit (absolutely positioned, no
       max-width), so it grows to the longest label rather than wrapping —
       adaptive to any label length, including a future i18n pass, where a
       fixed min-width would not be. */
    white-space: nowrap;
}

.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;
}

/* SNOW-324: field-report roundel. Reuses .map-utility-pill for the 40×40
   glass-circle look, but anchored bottom-right inside #map and floated
   above the season scrubber (bottom 5px + ~43px pill, + safe-area), level
   with the date pill, so it never overlaps the timeline. The
   warning-triangle icon is tinted amber (status-warning) to stand out as
   the report-a-hazard action; the SVG strokes inherit it via currentColor. */
.map-report-control {
    position: absolute;
    right: calc(env(safe-area-inset-right, 0px) + 12px);
    bottom: calc(env(safe-area-inset-bottom, 0px) + 60px);
    width: 40px;
    justify-content: center;
    z-index: 4;
    color: var(--color-status-warning-text);
}

.map-report-control:hover {
    filter: brightness(1.04);
}

/* 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;
    /* PROTOTYPE (homepage rework): (i) legend moves to the bottom-left corner,
       horizontally level with the report roundel (bottom:60px). */
    left: calc(env(safe-area-inset-left, 0px) + 12px);
    bottom: calc(env(safe-area-inset-bottom, 0px) + 60px);
    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;
    /* PROTOTYPE: anchor to the right of the (i) toggle, bottom-aligned so the
       card grows upward from the bottom-left corner. */
    left: 40px;              /* 32px button + 8px gap */
    bottom: 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.
   ————————————————————————————————————————————————————————— */

/* PROTOTYPE (homepage rework): the season header (#region-readout) moves
   from the bottom — where it sat above the scrubber — to the top bar,
   centred between the (i) legend toggle (top-left) and the utility cluster
   (top-right). Since SNOW-314 this container holds only the readout chip
   (the per-day colour cells live in .scrubber-ribbon inside the scrubber),
   so repositioning it relocates the header alone; the scrubber stays put.
   z-index 3 keeps it above the choropleth and level with the legend. */
.season-ribbon {
    position: absolute;
    /* PROTOTYPE (homepage rework): season header pulled to the top-left,
       vertically centred against the 40px search roundel (top:12px) so the
       location readout and the search sit on one line with the row between
       them free. */
    top: calc(env(safe-area-inset-top, 0px) + 18px);
    left: calc(env(safe-area-inset-left, 0px) + 12px);
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
}

.ribbon-header {
    display: flex;
    align-items: center;
    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);
    /* PROTOTYPE (homepage rework): the pill is now an info display (a <div>);
       the bulletin link is the separate .region-readout-action roundel. */
    color: var(--ink);
}

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

/* PROTOTYPE (homepage rework): breadcrumb prefix (Major › Minor ›) — muted and
   regular weight so the micro-region leaf carries the emphasis. Hidden on
   mobile (see the max-width:640px block below). */
.region-readout-crumbs {
    font-weight: 400;
    color: var(--muted);
}

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

/* PROTOTYPE (homepage rework): the "view bulletin" action is a separate
   roundel (a glass circle with an arrow + a "View bulletin" tooltip), sitting
   to the right of the readout pill. Hidden by default; shown only when a region
   is focused (the sibling rule below), so there is always a bulletin to open. */
.region-readout-action {
    display: none;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    flex: 0 0 auto;
    border-radius: 999px;
    color: var(--ink);
    background: rgba(255, 255, 255, 0.75);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    border: 0.5px solid var(--border);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
    text-decoration: none;
    transition: box-shadow 120ms ease, background 120ms ease;
}

#region-readout.has-region ~ .region-readout-action {
    display: inline-flex;
}

.region-readout-action:hover,
.region-readout-action: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-action {
        transition: none;
    }
}

/* PROTOTYPE (homepage rework): on narrow viewports the breadcrumb prefix
   (Major › Minor ›) is dropped below 640px so the chip clears the search
   roundel; the leaf and the action roundel stay. */
@media (max-width: 640px) {
    .region-readout-crumbs {
        display: none;
    }
}

/* No region focused → date-only: drop the swatch and name so the chip reads as
   a plain date (the action roundel is already hidden by its own sibling rule). */
.region-readout:not(.has-region) .region-readout-swatch,
.region-readout:not(.has-region) .region-readout-name {
    display: none;
}

/* PROTOTYPE (homepage rework): the date leads the chip — mono, fixed-width
   (the readout is mono throughout), and muted so the region name carries the
   emphasis. */
.region-readout-date {
    color: var(--muted);
}

/* Colour block dividing the date from the region name; the background is the
   EAWS danger colour, set inline by map.js (transparent when no_rating). */
.region-readout-swatch {
    width: 10px;
    height: 10px;
    flex: 0 0 auto;
    border-radius: 2px;
    background: 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;
}

/* SNOW-343: persistent off-season archive chip — bottom-left of #map,
   beside the 32px (i) legend toggle. Left offset clears the toggle (32px)
   plus an 8px gap; bottom matches .map-legend so they share a baseline.
   pointer-events: none so map clicks pass through. */
.map-offseason-note {
    position: absolute;
    left: calc(env(safe-area-inset-left, 0px) + 52px);
    bottom: calc(env(safe-area-inset-bottom, 0px) + 60px);
    z-index: 3;
    /* Match the 32px legend roundel's height so, sharing the same bottom
       baseline, the chip is vertically centred on it rather than reading as
       bottom-anchored to it. */
    height: 32px;
    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-3);
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    white-space: nowrap;
    max-width: calc(100% - 120px);
    pointer-events: none;
    user-select: none;
}

/* Off-season reference line inside the intro card — rendered only when
   is_offseason is True. The persistent chip (.map-offseason-note) is the
   bottom-left counterpart that survives #home-intro dismissal. */
.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);
}
