/* ── Typeface ────────────────────────────────────────────────────────────────
   Inter, self-hosted as a single variable woff2 per subset (SIL Open Font
   License 1.1, Rasmus Andersson). Replaces a render-blocking @import of DM Sans
   and Plus Jakarta Sans from Google Fonts: that import sat in front of first
   paint and leaked every visitor's IP to a third party, which is worth avoiding
   for a public-health page.

   One variable file covers weight 100–900, so the whole range costs a single
   request. latin-ext is split out and gated on its unicode-range, so it is only
   fetched if a glyph outside latin actually appears — the French UI needs it
   for œ and for the accents that fall outside latin-1.

   The licensed brand faces (Agrandir display, Apercu text) were referenced here
   by @font-face but the files were never added to assets/, so every page load
   fired four 404s and silently fell back. Those rules are removed rather than
   left dangling; the family names are kept at the head of the stacks below, so
   dropping the real files in and restoring an @font-face block is all it takes
   to activate them. */
@font-face {
    font-family: 'Inter';
    src: url('/assets/Inter-Variable-latin.woff2') format('woff2');
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

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

/* ── Condensed sticky KPI bar ─────────────────────────────────────────────────
   Appears once the full KPI strip scrolls out of view. Visibility is toggled by
   assets/sticky-kpi.js; everything below is presentation only.

   z-index 1002 is deliberate and must stay above the map's floating level
   toggle (1000) and its hover panel (1001) — both live inside the scrolling
   content and would otherwise paint over a pinned bar while you scroll past
   the map. */
.sticky-kpi {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1002;
    display: flex;
    align-items: center;
    gap: 24px;
    height: 48px;
    padding: 0 32px;
    background-color: rgba(255, 255, 255, 0.82);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 1px solid rgba(15, 20, 25, 0.08);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";

    /* Hidden state. visibility is delayed by the transition duration so the bar
       stays keyboard- and screen-reader-inert once it has finished sliding out,
       rather than lingering as a focusable strip off the top of the page. */
    transform: translateY(-100%);
    opacity: 0;
    visibility: hidden;
    transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1),
                opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),
                visibility 0s linear 0.2s;
}

.sticky-kpi.is-visible {
    transform: translateY(0);
    opacity: 1;
    visibility: visible;
    transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1),
                opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),
                visibility 0s linear 0s;
}

/* 48px out of a short viewport is not a good trade — the page already carries a
   fixed footer bar. */
@media (max-height: 700px) {
    .sticky-kpi { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .sticky-kpi,
    .sticky-kpi.is-visible { transition: none; }
}

/* ── Data-flags panel ─────────────────────────────────────────────────────────
   Collapsed by default; the chip-bar button toggles .is-open. Animating
   max-height rather than height because the panel's natural height depends on
   how many flags fired and how far the unit lists wrap — there is no fixed value
   to transition to. The open value only needs to exceed any real height; it is
   a ceiling, not a size. */
.flags-panel {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}

.flags-panel.is-open {
    max-height: 600px;
}

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

/* The toggle sits in a row of plain chips, so the button's own chrome has to go
   — otherwise it reads as a form control dropped into a data strip. */
.flag-chip-btn {
    background: none;
    border: none;
    font: inherit;
    cursor: pointer;
    text-align: left;
    -webkit-appearance: none;
    appearance: none;
    transition: opacity 0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

.flag-chip-btn:hover { opacity: 0.7; }

.flag-chip-btn:focus-visible {
    outline: 2px solid #1e3a5c;
    outline-offset: 2px;
}

.flag-chip-caret {
    font-size: 9px;
    color: #6b7280;
    margin-left: 2px;
    display: inline-block;
    transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Caret follows the panel, so the control always states the panel's condition */
.flag-chip-btn[aria-expanded="true"] .flag-chip-caret {
    transform: rotate(180deg);
}

/* ── Base ──────────────────────────────────────────────────────────────────── */

* { box-sizing: border-box; }

:root {
    --Dash-Fill-Interactive-Strong: #1e3a5c;
}

body {
    background-color: #f5f5f7;
    margin: 0;
    font-family: 'Apercu', 'Inter', system-ui, sans-serif;
}

/* ── Tabular numerals ─────────────────────────────────────────────────────────
   Proportional digits change width as they change value, so every figure that
   updates in place — the KPI strip, the zone table, the slider's date readout —
   shifts sideways while the slider scrubs or the map animation plays. Fixed-
   width digits hold the layout still. */
#stats-bar,
#ir-table,
#data-flags,
#slider-date-display,
#slider-day-display,
#header-eyebrow,
#header-wow {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

/* ── Header font — Agrandir Bold (falls back to Plus Jakarta Sans) ─────────────── */
.app-header-title {
    font-family: 'Agrandir', 'Inter', system-ui, sans-serif !important;
    font-weight: 800 !important;
    letter-spacing: -0.03em !important;
}

/* Hide radio inputs inside toggles so they don't inflate label widths */
.view-toggle-radio input[type="radio"],
.level-toggle-radio input[type="radio"],
.chart-type-radio input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    margin: 0;
    padding: 0;
    pointer-events: none;
}

/* Dash 4 adds margin-right: 16px to each inline radio option — remove it
   so the last option sits flush with the container and the thumb aligns */
.view-toggle-radio .dash-options-list-option,
.level-toggle-radio .dash-options-list-option,
.chart-type-radio .dash-options-list-option {
    margin-right: 0 !important;
    margin-left: 0 !important;
}

/* ── Segmented control — shared base ────────────────────────────────────────── */

/* Neutral track, navy thumb: the accent earns its meaning by marking the one
   selected segment rather than tinting the whole control. */
.view-toggle-radio,
.level-toggle-radio,
.chart-type-radio {
    display: inline-flex;
    align-items: center;
    position: relative;
    background-color: #f1f2f4;
    border: 1px solid rgba(15,20,25,0.08);
    border-radius: 10px;
    padding: 3px;
    gap: 0;
}

/* When level-toggle floats over the map, frosted-glass that blends with the map */
.level-toggle-radio {
    background-color: rgba(255,255,255,0.72);
    border-color: rgba(0,0,0,0.08);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    box-shadow: 0 1px 8px rgba(0,0,0,0.10);
}

.level-toggle-radio label {
    color: rgba(20,40,65,0.80);
}

.level-toggle-radio .toggle-thumb {
    background-color: rgba(30,58,92,0.82);
}

/* Sliding thumb — navy pill that moves between options */
.toggle-thumb {
    position: absolute;
    border-radius: 7px;
    background-color: #1e3a5c;
    pointer-events: none;
    z-index: 0;
    transition: left 0.22s cubic-bezier(0.4, 0, 0.2, 1),
                top  0.22s cubic-bezier(0.4, 0, 0.2, 1),
                width 0.22s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Labels sit above the thumb; off state: transparent track + black text */
.view-toggle-radio label,
.level-toggle-radio label,
.chart-type-radio label {
    position: relative;
    z-index: 1;
    display: inline-block;
    padding: 5px 14px;
    border-radius: 7px;
    cursor: pointer;
    background: transparent;
    color: #3d4551;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.02em;
    transition: color 0.15s cubic-bezier(0.4, 0, 0.2, 1);
    user-select: none;
    white-space: nowrap;
}

/* Unselected segments respond to hover — interaction density without motion */
.view-toggle-radio label:hover:not(:has(input:checked)):not(:has(input:disabled)),
.level-toggle-radio label:hover:not(:has(input:checked)):not(:has(input:disabled)),
.chart-type-radio label:hover:not(:has(input:checked)):not(:has(input:disabled)) {
    color: #0f1419;
}

/* Active label text flips to white once the navy thumb is behind it */
.view-toggle-radio label:has(input[type="radio"]:checked),
.level-toggle-radio label:has(input[type="radio"]:checked),
.chart-type-radio label:has(input[type="radio"]:checked) {
    color: #ffffff;
}

/* Disabled chart-type options (Surveillance/Lab at zone level, where that data
   isn't tracked) — dim and block the click */
.chart-type-radio label:has(input[type="radio"]:disabled) {
    color: #b6bcc4 !important;
    cursor: not-allowed;
}

/* ── Map/Treemap view toggle — larger than the lang toggle ──────────────────────── */

.view-toggle-lg label {
    padding: 8px 22px !important;
    font-size: 14px !important;
}

/* ── Interactive surfaces ─────────────────────────────────────────────────────
   Hover changes the surface, not the geometry. Lifting a card on hover
   (translateY + a large drop shadow, on a spring curve that overshoots) reads
   as dated and, on the zone list, made a 40-row table wobble under the cursor.
   A tint plus a border change carries the same affordance while the layout
   stays still. Shadows are reserved for genuinely floating things — the
   frosted level-toggle over the map. */

.reset-btn,
.ir-row-btn {
    transition: background-color 0.15s cubic-bezier(0.4, 0, 0.2, 1),
                border-color     0.15s cubic-bezier(0.4, 0, 0.2, 1),
                color            0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* ── Reset view button — matches the off-state of the toggle segments ─────────── */

.reset-btn {
    display: inline-block;
    padding: 5px 14px;
    border-radius: 8px;
    border: 1px solid rgba(15,20,25,0.10);
    background-color: #f1f2f4;
    color: #3d4551;
    cursor: pointer;
}

.reset-btn:hover:not(:disabled) {
    background-color: #1e3a5c;
    border-color: #1e3a5c;
    color: #ffffff;
}

.reset-btn:active:not(:disabled) {
    background-color: #162d47;
    border-color: #162d47;
}

/* Keyboard focus must be visible even though hover is a colour change */
.reset-btn:focus-visible,
.ir-row-btn:focus-visible {
    outline: 2px solid #1e3a5c;
    outline-offset: 2px;
}

.reset-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* ── IR list row buttons ─────────────────────────────────────────────────────── */

.ir-row-btn {
    background: none;
    border-left: 2px solid transparent;
    cursor: pointer;
}

.ir-row-btn:hover {
    background: rgba(30,58,92,0.05);
    border-left-color: #1e3a5c;
}

/* ── Global catch-all: any radio/checkbox label defaults to dark ─────────────── */

label {
    color: #111111;
}

/* ── Date slider ─────────────────────────────────────────────────────────────── */

/* Track */
.rc-slider-rail {
    background-color: #d0d0d0 !important;
    height: 3px !important;
}

.rc-slider-track {
    background-color: #1e3a5c !important;
    height: 3px !important;
}

/* Handle */
.rc-slider-handle {
    border-color: #1e3a5c !important;
    background-color: #1e3a5c !important;
    width: 14px !important;
    height: 14px !important;
    margin-top: -5px !important;
    opacity: 1 !important;
    box-shadow: 0 0 0 3px rgba(30,58,92,0.2) !important;
}

.rc-slider-handle:hover,
.rc-slider-handle:active {
    box-shadow: 0 0 0 5px rgba(30,58,92,0.25) !important;
}

/* Dash 4 native range input fallback */
#date-slider input[type="range"] {
    accent-color: #1e3a5c;
}
[class*="rc-slider-track"],
[class*="SliderTrack"] {
    background-color: #1e3a5c !important;
}
[class*="rc-slider-handle"],
[class*="SliderHandle"] {
    border-color: #1e3a5c !important;
    background-color: #1e3a5c !important;
}

.dash-slider-root {
    --slider-color: #1e3a5c !important;
    --accent: #1e3a5c !important;
    --primary: #1e3a5c !important;
    --color-primary: #1e3a5c !important;
    --color-accent: #1e3a5c !important;
    --track-color: #1e3a5c !important;
    --fill-color: #1e3a5c !important;
    --interactive-color: #1e3a5c !important;
    --strong-color: #1e3a5c !important;
}

#date-slider .dash.fill.interactive.strong,
#date-slider .fill.interactive.strong,
#date-slider .fill.strong {
    background-color: #1e3a5c !important;
    border-color: #1e3a5c !important;
}

.dash-slider-thumb {
    background-color: #1e3a5c !important;
    border-color: #1e3a5c !important;
    box-shadow: none !important;
}

.dash-slider-thumb:hover,
.dash-slider-thumb:focus,
.dash-slider-thumb:active {
    background-color: #1e3a5c !important;
    box-shadow: 0 0 0 4px rgba(30,58,92,0.2) !important;
}

/* Tick marks */
.rc-slider-mark-text {
    color: #6b7280 !important;
    font-size: 10px !important;
    font-family: 'Inter', system-ui, sans-serif !important;
    margin-top: 4px !important;
}

/* Hide the raw index-number tooltip and Dash 4's editable input beside the handle */
.rc-slider-tooltip,
.rc-slider-tooltip-inner,
[class*="slider-tooltip"],
[class*="SliderTooltip"],
#date-slider input,
#date-slider [role="tooltip"],
#date-slider [class*="tooltip"],
#date-slider [class*="handle-label"],
#date-slider [class*="Tooltip"],
#date-slider [class*="Input"] {
    display: none !important;
    opacity: 0 !important;
    visibility: hidden !important;
    pointer-events: none !important;
}

/* ── Treemap tile lift ───────────────────────────────────────────────────────── */

/* Let the shadow bleed outside the SVG canvas */
#treemap .main-svg,
#treemap svg {
    overflow: visible !important;
}

/* Base transition on every tile. The lift is kept here — unlike the buttons,
   a treemap tile has no border or background of its own to tint, and the lift
   is the only cue that a tile is clickable. Retuned off the spring curve onto
   the same ease-out as everything else, with a softer shadow. */
#treemap g.slice {
    transition: transform 0.15s cubic-bezier(0.4, 0, 0.2, 1),
                filter   0.15s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Lifted state — set by JS mouseenter so only the topmost tile activates */
#treemap g.slice.slice-lift {
    transform: translateY(-2px);
    filter: drop-shadow(0 4px 12px rgba(15, 20, 25, 0.16));
}

/* Hide Plotly's hover label anchor arrow on the choropleth map */
#choropleth-map .hovertext {
    display: none !important;
}

/* Crosshair cursor over the choropleth map — covers Plotly drag layers,
   MapLibre/Mapbox canvas, and any element Plotly sets dynamically */
#choropleth-map,
#choropleth-map *,
#choropleth-map canvas,
#choropleth-map .mapboxgl-canvas,
#choropleth-map .mapboxgl-canvas-container,
#choropleth-map .mapboxgl-interactive,
#choropleth-map .maplibregl-canvas,
#choropleth-map .maplibregl-canvas-container,
#choropleth-map .maplibregl-interactive,
#choropleth-map .nsewdrag,
#choropleth-map .nsdrag,
#choropleth-map .ewdrag,
#choropleth-map .drag {
    cursor: crosshair !important;
}

/* ── Zone rankings DataTable ─────────────────────────────────────────────────── */

/* Remove all cell borders that Dash injects by default */
#ir-table .dash-spreadsheet-container .dash-spreadsheet,
#ir-table .dash-spreadsheet-container .dash-spreadsheet td,
#ir-table .dash-spreadsheet-container .dash-spreadsheet th {
    border: none !important;
    box-shadow: none !important;
}

/* Row hover — highlight entire row */
#ir-table .dash-spreadsheet-container tbody tr:hover td.dash-cell {
    background-color: rgba(200, 220, 238, 0.35) !important;
    cursor: pointer;
}

/* Active / selected cell — no blue outline ring */
#ir-table .dash-spreadsheet-container td.dash-cell.focused {
    outline: none !important;
    box-shadow: none !important;
}

/* ── Footer ──────────────────────────────────────────────────────────────────── */

/* No extra margin above footer */
body > div:last-child {
    margin-top: 0;
}

/* Invisible scrollbar for the incidence ranking list */
.no-scrollbar {
    scrollbar-width: none;       /* Firefox */
    -ms-overflow-style: none;    /* IE / Edge */
}
.no-scrollbar::-webkit-scrollbar {
    display: none;               /* Chrome / Safari */
}
