/* ── Design tokens ─────────────────────────────────────────────── */
/* CSS custom properties (variables) -- the single source of truth for
   colors/shadows/radius used throughout this whole file via var(--name).
   Change a color scheme here once instead of hunting down every hardcoded
   hex value. Defined on :root so they're available to every selector on the page. */
:root {
  --bg:        #f8fafc;   /* page background */
  --panel:     #ffffff;    /* card/panel background (white) */
  --muted:     #64748b;     /* secondary/dimmed text color */
  --text:      #0f172a;      /* primary text color */
  --border:    #e2e8f0;       /* light border color, most common */
  --border-2:  #cbd5e1;        /* slightly darker border, used for inputs/dropdowns */
  --shadow:    0 4px 6px -1px rgba(0,0,0,.10), 0 2px 4px -1px rgba(0,0,0,.06);     /* larger elevation shadow (cards on hover, chart panel) */
  --shadow-sm: 0 1px 3px 0 rgba(0,0,0,.08),   0 1px 2px 0 rgba(0,0,0,.04);         /* smaller/subtler shadow (default card state) */
  --primary:   #3b82f6;   /* main brand blue */
  --primary-2: #2563eb;    /* darker blue, used for hover states / links */
  --success:   #10b981;   /* green, used for citizen-science accents and success states */
  --success-2: #059669;    /* darker green, hover state */
  --radius:    8px;   /* standard corner rounding used almost everywhere */
}

/* ── Reset ─────────────────────────────────────────────────────── */
/* Removes every browser's inconsistent default margin/padding and forces
   border-box sizing (so padding/border are included IN an element's
   declared width, not added on top of it) -- applied to literally every
   element, plus their ::before/::after pseudo-elements. */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;    /* lets .app-wrapper below fill the full viewport height */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  /* "System font stack" -- uses whatever native UI font the visitor's own
     OS provides (San Francisco on Mac, Segoe UI on Windows, Roboto on
     Android/Chrome OS) instead of loading a custom web font, for speed and
     a familiar native feel. */
  font-size: 14px;
  color: var(--text);
  background: var(--bg);
}

/* ── App wrapper ───────────────────────────────────────────────── */
/* Outermost layout container (see index.html) -- a full-height flex
   column holding the header on top and the scrollable body below it.
   overflow:hidden here (combined with height:100vh) is what stops the
   whole page itself from scrolling -- scrolling instead happens inside
   .app-main further down. */
.app-wrapper { display: flex; flex-direction: column; height: 100vh; overflow: hidden; }

/* ── Full-width header ─────────────────────────────────────────── */
.app-header {
  min-height: 120px;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  row-gap: 6px;
  padding: 6px 16px;
  flex: 0 0 auto;   /* the header block itself never grows/shrinks against the body below it */
}

.app-title {
  /* Note: index.html's actual logo/title markup uses a plain <img> inside
     .app-title now (not a separate text label) -- these text-styling rules
     (font-weight/size/color) are effectively unused leftovers from an
     earlier version of the header that showed a text title next to the logo. */
  font-weight: 800;
  font-size: 22px;
  letter-spacing: .01em;
  color: var(--text);
  transition: color .18s, opacity .18s;
  user-select: none;   /* stops the title text from being selectable/highlightable like a button label would be */
}
.app-title:hover {
  opacity: .8;   /* subtle dim-on-hover, reinforcing that the logo area is clickable (see index.html's onclick="showPage('landing')") */
}

.title-icon {
  /* Also appears to be an unused leftover -- no matching element in the current index.html. */
  width: 22px; height: 22px;
  border-radius: 5px;
  background: #e2e8f0;
  border: 1px solid var(--border);
  flex: 0 0 auto;
}

/* ── Body: sidebar + main ──────────────────────────────────────── */
.app-body {
  display: flex;
  flex: 1;   /* fills all remaining height below the fixed-height header */
  overflow: hidden;
  /* Three soft, barely-visible radial color blobs layered over the flat
     background color -- a subtle decorative gradient wash rather than a
     plain solid background. */
  background:
    radial-gradient(circle at 10% 0%,  rgba(59,130,246,.10) 0%, transparent 40%),
    radial-gradient(circle at 90% 10%, rgba(16,185,129,.08) 0%, transparent 45%),
    radial-gradient(circle at 60% 90%, rgba(245,158,11,.06) 0%, transparent 45%),
    var(--bg);
}

/* ── Sidebar (floating map panel) ──────────────────────────────── */
/* The filter panel that floats on top of the landing page's map (see
   index.html's <aside class="sidebar">). Positioned absolutely relative to
   the nearest positioned ancestor, .map-area (see further down). */
.sidebar {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 1000;   /* high enough to sit above the Leaflet map's own internal layers (tiles, markers, controls) */
  width: 230px;
  max-height: 340px;
  overflow-y: auto;   /* scrolls internally if its filter sections don't all fit in 340px */
  background: rgba(255,255,255,0.97);   /* near-opaque white -- lets a hint of the map show through at the very edges */
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 4px 20px rgba(0,0,0,0.18);   /* a stronger, more custom shadow than --shadow/--shadow-sm, to really lift this panel visually off the map underneath it */
  padding: 12px 14px 16px;
  transition: transform 0.2s ease, opacity 0.2s ease;
}
.sidebar.panel-collapsed {
  /* Slides the whole panel out to the left (past its own width, plus a
     12px gap) and fades it out, rather than just display:none-ing it --
     this is what makes toggleMapPanel() in app.js produce a smooth slide
     animation instead of an instant hide. */
  transform: translateX(calc(-100% - 12px));
  opacity: 0;
  pointer-events: none;   /* also stops the (now invisible) panel from intercepting clicks meant for the map underneath it */
}
.sidebar-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 10px;
}
.sidebar-header-title { font-size: 13px; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }
.sidebar-header-actions { display: flex; align-items: center; gap: 5px; }
.sidebar-clear-btn {
  background: none; border: none; cursor: pointer;
  font-size: 11px; font-weight: 600; color: var(--primary); padding: 3px 5px; border-radius: 4px;
}
.sidebar-clear-btn:hover { background: #eff6ff; }
.sidebar-clear-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.sidebar-close-btn {
  background: none; border: none; cursor: pointer;
  font-size: 18px; color: var(--muted); line-height: 1; padding: 2px 4px; border-radius: 4px;
}
.sidebar-close-btn:hover { background: var(--border-2); }

/* The "☰ Filters" button that appears once the sidebar above is collapsed
   -- reopens it (see toggleMapPanel() in app.js). */
.map-panel-toggle {
  position: absolute;
  top: 10px; left: 10px;   /* same corner the sidebar itself sits in, so it visually "replaces" the collapsed panel */
  z-index: 1001;   /* one above the sidebar's own z-index, though moot since the sidebar is invisible (opacity:0) whenever this button is shown */
  pointer-events: all;
  background: white;
  border: 2px solid rgba(0,0,0,0.2);
  border-radius: 4px;
  padding: 6px 10px;
  cursor: pointer;
  font-size: 13px; font-weight: 600; color: #333;
  display: none; align-items: center; gap: 5px;   /* display:none by default -- app.js toggles the .visible class below to actually show it */
  box-shadow: 0 1px 5px rgba(0,0,0,0.15);
}
.map-panel-toggle.visible { display: flex; }

.sb-section { margin-bottom: 4px; }   /* "sb-" prefix throughout this file = "sidebar" -- groups one labeled block of filter controls (e.g. "Sensor Categories") */

.sb-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 8px;
}

.sb-check {
  /* One checkbox + label row, e.g. "☑ Air" in the Sensor Categories section. */
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  padding: 4px 6px;
  margin-bottom: 2px;
  border: 1px solid transparent;
  border-radius: 6px;
  cursor: pointer;
  color: var(--text);
  transition: background .15s, border-color .15s;
}
.sb-check:hover,
.sb-check:has(input:checked) {
  background: var(--filter-tint, #f8fafc);
  border-color: var(--filter-border, #cbd5e1);
}
.sb-check:has(input:checked) { font-weight: 600; }
.sb-check input { cursor: pointer; accent-color: var(--filter-color, var(--primary)); }

/* Match each filter row to its map marker through the checkbox and tint while
   preserving dark label text. */
.filter-breathe { --filter-color: #00a6a6; --filter-tint: #e8f8f8; --filter-border: #9bdada; }
.filter-build   { --filter-color: #d85f32; --filter-tint: #fdf0eb; --filter-border: #efb7a1; }
.filter-grow    { --filter-color: #3a8d3f; --filter-tint: #edf6ee; --filter-border: #afd1b1; }
.filter-move    { --filter-color: #7b4db2; --filter-tint: #f3eef8; --filter-border: #cbb9df; }
.filter-pulse   { --filter-color: #d99a00; --filter-tint: #fff8e6; --filter-border: #ebcf80; }
.filter-swim    { --filter-color: #2364aa; --filter-tint: #edf3fa; --filter-border: #a7c1df; }
.filter-other   { --filter-color: #64748b; --filter-tint: #f1f5f9; --filter-border: #cbd5e1; }
.filter-citizen { --filter-color: #b3261e; --filter-tint: #fbeceb; --filter-border: #e1a39f; }

.sb-hr { border: none; border-top: 1px solid var(--border-2); margin: 14px 0; }   /* thin divider between filter sections, styled as a 1px top border rather than the browser's default 3D-inset <hr> look */

/* Sidebar input controls */
.sb-control-wrap { position: relative; }   /* positioning anchor for a dropdown menu (.sb-dropdown below) to appear directly beneath its trigger input */

.sb-input {
  /* Shared base style for both the sensor-search text input and the
     custom research-group dropdown trigger (a styled <div>, not a real
     <select> -- see .sb-select below). */
  width: 100%;
  padding: 5px 8px;
  border: 1px solid var(--border-2);
  border-radius: 4px;
  font-size: 13px;
  background: #fff;
  color: var(--text);
  line-height: 1.5;
  min-height: 32px;
  display: flex;
  align-items: center;
}
input.sb-input { display: block; }   /* real <input> elements need block (not flex) display for their text/cursor to behave normally -- flex is only wanted on the div-based trigger version */
input.sb-input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 2px rgba(59,130,246,.2); }
/* outline:none removes the default browser focus ring; the border-color +
   box-shadow combo replaces it with a custom blue "glow" -- still visibly
   focused for accessibility, just styled to match the rest of the app. */

.sb-select {
  cursor: pointer;
  user-select: none;   /* it's a fake "dropdown trigger", not real text -- shouldn't be selectable/highlightable */
}
.sb-select:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 2px rgba(59,130,246,.2); }
.sb-select:hover { border-color: var(--border-2); background: #fafafa; }

/* Dropdown */
/* Shared popover style for every custom dropdown menu in the sidebar
   (sensor search results, research group checklist). */
.sb-dropdown {
  position: absolute;
  top: calc(100% + 2px);   /* sits directly below its trigger, with a small 2px gap -- calc() needed since "100%" alone (of the parent) plus a fixed pixel gap can't be expressed as a single unit */
  left: 0; right: 0;   /* stretches to match its trigger's full width */
  background: var(--panel);
  border: 1px solid var(--border-2);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  z-index: 500;   /* above normal page content, but well below the sidebar itself (1000) or map panel toggle (1001), since it only ever needs to float above nearby sidebar content */
  max-height: 220px;
  overflow-y: auto;
}

.sb-dropdown-item {
  /* One clickable row in the sensor-search results dropdown. */
  padding: 7px 10px;
  font-size: 13px;
  cursor: pointer;
  color: var(--text);
}
.sb-dropdown-item:hover { background: #f1f5f9; }

.sb-check-item {
  /* One checkbox row inside the research-group dropdown -- similar to
     .sb-check above, but sized/spaced for use inside a dropdown popover
     rather than directly in the sidebar's main flow. */
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 6px 10px;
  font-size: 13px;
  cursor: pointer;
  color: var(--text);
  line-height: 1.4;
}
.sb-check-item:hover { background: #f1f5f9; }
.sb-check-item input { margin-top: 2px; flex: 0 0 auto; accent-color: var(--primary); cursor: pointer; }

.sb-dropdown-header {
  /* The "Research Group  [Select All]" row pinned to the top of the group dropdown. */
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 7px 10px 5px;
  border-bottom: 1px solid var(--border);
  font-size: 11px;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .06em;
}
.sb-dropdown-header a {
  color: var(--primary); cursor: pointer; font-weight: 600; font-size: 11px;
  text-decoration: none;
}
.sb-dropdown-header a:hover { text-decoration: underline; }

/* Sensor chips */
/* Small removable "pill" tags shown below the sensor search box, one per
   currently-selected sensor (see renderSensorChips() in app.js). */
.sb-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 5px; }

.sb-chip {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px 5px 2px 7px;   /* asymmetric padding -- slightly less on the right to make room for the × button's own padding, so the two don't look unbalanced */
  background: #dbeafe;
  border: 1px solid #bfdbfe;
  border-radius: 10px;
  font-size: 11px;
  font-weight: 600;
  color: #1e40af;
  max-width: 190px;   /* caps how wide one chip can grow -- a long sensor name gets truncated (see .sb-chip span below) rather than stretching the sidebar layout */
}
.sb-chip span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }   /* truncates an overly-long chip label with a "…" ellipsis */
.sb-chip-x {
  background: none; border: none; cursor: pointer;
  color: #93c5fd; font-size: 14px; padding: 0 1px; line-height: 1;
}
.sb-chip-x:hover { color: #1e40af; }

/* ── Main content ──────────────────────────────────────────────── */
.app-main {
  flex: 1;   /* fills all width to the right of/below the header, since .app-body is a flex row/column context */
  padding: 14px;
  overflow-y: auto;   /* this is where actual page scrolling happens (see the .app-wrapper comment above) */
  min-width: 0;   /* without this, flex children default to a min-width based on their content, which can force unwanted horizontal overflow/scrolling on a wide table or chart */
}

/* ── Page sections (replaces tabs) ────────────────────────────── */
/* Only one of the 4 <section class="page-content"> elements in index.html
   is visible at a time -- showPage() in app.js toggles which one has the
   .active class. */
.page-content { display: none; padding: 20px; }
.page-content.active { display: block; }


/* Nav row inside pages — top position */
.page-nav-row {
  display: flex; justify-content: space-between; align-items: center;
  /* Negative margins pull this row out to the very edges of its parent
     .page-content (which has 20px padding, per the rule above) -- lets
     this specific row have its own full-bleed background/border-bottom
     that spans edge-to-edge, rather than being inset like the rest of the page content. */
  margin: -20px -20px 16px -20px;
  padding: 10px 20px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  gap: 10px;
}

/* Landing-page map heading and related action */
.map-section-heading {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 10px;
}
.map-section-copy { min-width: 0; }
.map-section-title {
  margin: 0;
  font-size: 20px;
  font-weight: 800;
  line-height: 1.25;
  color: var(--primary);
}
.map-section-description {
  margin: 3px 0 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}
.map-section-actions { flex: 0 0 auto; }

/* ── Tab card (kept for reference, no longer used) ─────────────── */
/* This whole block (through .tab-content below) is dead CSS -- leftover
   from an earlier tabbed-interface design that was replaced by the
   current separate-page (.page-content) approach above. No matching
   elements exist in the current index.html. Kept only as a reference in
   case a tabbed layout is ever reintroduced -- safe to delete otherwise. */
.tab-card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: visible;
}

.tab-nav {
  display: flex;
  border-bottom: 1px solid var(--border);
  padding: 0 4px;
  background: transparent;
  flex-wrap: nowrap;
}

.tab-btn {
  padding: 10px 16px;
  border: 1px solid transparent;
  border-bottom: none;
  background: transparent;
  cursor: pointer;
  font-size: 13px;
  font-weight: 500;
  color: var(--primary-2);
  border-radius: 4px 4px 0 0;
  margin-bottom: -1px;   /* pulls this tab button down 1px so its bottom edge overlaps/hides the .tab-nav container's border-bottom directly beneath the active tab, creating a seamless "attached" look */
  white-space: nowrap;
  transition: background .1s;
}
.tab-btn:hover { background: #f8fafc; color: var(--text); }
.tab-btn.active {
  background: var(--panel);
  color: var(--text);
  font-weight: 700;
  border-color: var(--border);
  border-bottom-color: var(--panel);   /* matches the panel's own background -- visually "erases" the bottom border right where the active tab sits, so it looks continuous with the content panel below it */
}

.tab-body { padding: 20px; }

/* ── Tab content ───────────────────────────────────────────────── */
.tab-content { display: none; }
.tab-content.active { display: block; }

/* ── Map wrappers ──────────────────────────────────────────────── */
.map-area {
  position: relative;   /* positioning anchor for the floating .sidebar filter panel and the .wind-legend-badge-style overlays elsewhere -- any absolutely-positioned child inside here is placed relative to this box, not the whole page */
  margin-bottom: 16px;
}
.map-wrapper {
  height: 460px;
  border-radius: var(--radius);
  overflow: hidden;   /* clips the square Leaflet map to this wrapper's rounded corners */
  border: 1px solid var(--border);
}
.map-wrapper > div { height: 100%; width: 100%; }
#landing-map, #summary-map, #waterloo-map { height: 100% !important; }   /* Leaflet's own JS sets an inline height style on this element -- !important is needed to reliably override that and force it to fill its wrapper instead */

/* Keep OpenStreetMap's detail while muting only the background tiles. Leaflet
   draws markers, popups, and controls in separate panes, so their category
   colors and contrast remain unchanged. */
.leaflet-tile-pane {
  filter: saturate(0.45) brightness(1.08) contrast(0.9);
}

.map-legend {
  /* The "Layer Legend" box, bottom-right of the map (see addLegend() in app.js). */
  background: rgba(255,255,255,.93);
  padding: 9px 12px;
  border-radius: 6px;
  font-size: 12px;
  box-shadow: var(--shadow-sm);
  line-height: 1.6;
}
.map-legend b { display: block; margin-bottom: 3px; font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); }
.map-legend-item { border-radius: 4px; margin-left: -4px; padding: 2px 4px; }   /* negative margin lets the hover-highlight background (below) extend slightly past the text's own edge without shifting the text's visible position */
.map-legend-item:hover { background: rgba(0,0,0,.06); }   /* each legend entry is clickable (filters the map to that type -- see filterMapToType() in app.js), so it gets a subtle hover affordance like a button would */
.map-legend-glyphs { display: flex; gap: 4px; margin-left: 2px; }
.map-legend-glyph {
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--c-citizen, #B3261E);
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.map-legend-glyph svg { width: 11px; height: 11px; fill: #fff; }

/* ── Citizen-science map markers ───────────────────────────────── */
/* Custom Leaflet DivIcon markers built by citizenMarkerIcon() in app.js:
   a coloured round badge holding a white program glyph (bird / flask /
   building-in-water) instead of a plain circleMarker dot. */
.cs-div-icon { background: none; border: 0; }   /* strip Leaflet's default .leaflet-div-icon white box */
.cs-marker {
  display: flex; align-items: center; justify-content: center;
  width: 100%; height: 100%;
  border-radius: 50%;
  background: #B3261E;                 /* Citizen Science red (matches TYPE_COLORS) */
  border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0,0,0,.45);
}
.cs-marker svg { width: 62%; height: 62%; fill: #fff; display: block; }

/* ── Activity heatmap ──────────────────────────────────────────── */
/* Styles for an hour-by-sensor activity heatmap grid. No matching
   "hm-*" elements exist in the current index.html -- likely built by a
   dashboard feature that's since been removed or never finished wiring
   up on the frontend, even though the backend route (/api/activity-heatmap)
   still exists (see api.py). Kept here in case it's reintroduced. */
.hm-title    { font-size: 15px; font-weight: 700; text-align: center; margin-bottom: 1px; }
.hm-subtitle { font-size: 12px; color: var(--muted); text-align: center; margin-bottom: 14px; }

/* outer flex: grid area + legend side by side */
.hm-outer    { display: flex; align-items: flex-start; gap: 8px; overflow-x: auto; }

/*
  Single CSS grid: first column = y-label, next 24 = data cells.
  All rows (sensors + x-axis row) live here so labels always align.
*/
.hm-grid {
  flex: 1;
  display: grid;
  grid-template-columns: minmax(90px, max-content) repeat(24, minmax(18px, 1fr));   /* first column sized to fit its label text (at least 90px); the other 24 columns (one per hour of day) share the remaining space equally, each at least 18px wide */
  gap: 2px;
}
.hm-ylabel {
  display: flex; align-items: center; justify-content: flex-end;
  padding-right: 8px; font-size: 11px; white-space: nowrap; color: var(--text);
  height: 26px;
}
.hm-cell {
  height: 26px; border-radius: 2px; cursor: default;
}
.hm-cell:hover { outline: 2px solid rgba(0,0,0,.4); position: relative; z-index: 1; }   /* z-index:1 lifts the hovered cell's outline above its neighboring cells, so the outline isn't partially covered by the next cell's edge */
.hm-corner { height: 22px; }   /* spacer in x-axis row, first col */
.hm-xlabel {
  height: 22px; font-size: 9px; color: var(--muted);
  display: flex; align-items: flex-start; justify-content: center;
  padding-top: 3px; white-space: nowrap;
}

/* legend: vertical gradient bar + ticks */
.hm-legend      { display: flex; flex-shrink: 0; gap: 4px; align-items: stretch; }
.hm-leg-bar     {
  width: 18px;
  background: linear-gradient(to bottom, rgb(50,0,120), rgb(130,60,190), rgb(215,190,240), #fff);   /* dark purple (most activity) fading to white (none) -- matches whatever color scale the heatmap cells themselves would use */
  border: 1px solid var(--border); border-radius: 3px;
  flex-shrink: 0;
}
.hm-leg-side    { display: flex; flex-direction: column; justify-content: space-between; }
.hm-leg-ticks   { display: flex; flex-direction: column; justify-content: space-between; font-size: 10px; color: var(--muted); flex: 1; }
.hm-leg-label   {
  font-size: 10px; color: var(--muted); writing-mode: vertical-rl;   /* rotates the text to read top-to-bottom instead of left-to-right */
  transform: rotate(180deg); text-align: center; align-self: center;   /* flips the vertical text 180° so it reads bottom-to-top instead (a common combo for a sideways axis label that should read upward) */
}

/* ── Intro hero ────────────────────────────────────────────────── */
/* Introductory banner at the top of the landing and Waterloo pages. */
.intro-top-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  align-items: stretch;
  gap: 14px;
  margin-bottom: 20px;
}
.intro-top-layout .intro-hero { margin-bottom: 0; }
.intro-hero {
  margin-bottom: 20px; padding: 20px 28px;
  border-radius: var(--radius); border: 1px solid var(--border);
  background: linear-gradient(135deg, #eff6ff 0%, #ffffff 60%, #f0fdf4 100%);   /* subtle diagonal wash from pale blue to white to pale green -- echoes the brand's blue/green color pairing without being a solid color block */
  box-shadow: var(--shadow-sm);
  display: flex; align-items: center;
}
.intro-hero-left { flex: 1; }
.intro-tagline {
  font-size: 22px; font-weight: 800; color: var(--text);
  line-height: 1.25; margin-bottom: 10px;
}
.intro-text {
  font-size: 14px; color: var(--muted); line-height: 1.65; margin: 0;
}
.intro-jump-link {
  padding: 18px 20px;
  border: 1px solid #86efac;
  border-radius: var(--radius);
  background: linear-gradient(135deg, #f0fdf4 0%, #ffffff 100%);
  color: #166534;
  font: inherit;
  font-size: 14px;
  line-height: 1.45;
  text-align: left;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 7px;
  transition: background .15s, border-color .15s, color .15s, transform .15s;
}
.intro-jump-link strong { font-size: 13px; }
.intro-jump-link:hover,
.intro-jump-link:focus-visible {
  background: #dcfce7;
  border-color: #86efac;
  color: #14532d;
  transform: translateY(-1px);
}
.intro-jump-link:focus-visible {
  outline: 3px solid rgba(22, 101, 52, .2);
  outline-offset: 2px;
}

/* ── Citizen Science ───────────────────────────────────────────── */
/* The green "CITIZEN SCIENCE AT UWATERLOO" section near the bottom of the landing page. */
.citizen-section {
  margin-bottom: 16px; padding: 20px 24px;
  border-radius: var(--radius); border: 1px solid #bbf7d0;
  background: linear-gradient(135deg, #f0fdf4 0%, #fff 100%);
  scroll-margin-top: 140px;
}
.citizen-heading { margin-bottom: 14px; }
.citizen-title { font-size: 18px; font-weight: 800; color: #166534; margin: 0 0 3px; }
.citizen-description { margin: 0; color: var(--muted); font-size: 13px; line-height: 1.5; }
.cs-toggles { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.cs-toggle {
  /* Pill-style toggle buttons for citizen-science sub-categories -- an
     alternative UI to the sidebar checkboxes that drives the same
     state.selectedCsCategories in app.js (see setupCsCheckboxes()). */
  padding: 5px 14px; border-radius: 999px; font-size: 12px; font-weight: 600;
  border: 2px solid #166534; color: #166534; background: transparent;
  cursor: pointer; transition: background .15s, color .15s;
}
.cs-toggle.active { background: #166534; color: #fff; }   /* filled-in state once toggled on -- inverts the outline style above */
.citizen-initiative-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.citizen-initiative-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
  padding: 16px;
  background: rgba(255,255,255,.9);
  border: 1px solid #bbf7d0;
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}
.citizen-initiative-copy { flex: 1; }
.citizen-initiative-title {
  margin: 0 0 5px;
  color: var(--text);
  font-size: 15px;
  font-weight: 750;
}
.citizen-initiative-description {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
  line-height: 1.5;
}
.citizen-initiative-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.citizen-initiative-actions .btn { min-width: 130px; }
.btn.citizen-summary-btn {
  background: #166534;
  color: #fff !important;
  border-color: #166534;
}
.btn.citizen-summary-btn:hover {
  background: #14532d;
  border-color: #14532d;
  transform: translateY(-1px);
}
.btn.citizen-submit-btn {
  background: #fff;
  color: #166534 !important;
  border-color: #86efac;
}
.btn.citizen-submit-btn:hover {
  background: #dcfce7;
  border-color: #4ade80;
  transform: translateY(-1px);
}

/* ── Summary grid ──────────────────────────────────────────────── */
/* The 3 stat cards below the landing page map (Total Sensors / # of Parameters / Participating Groups). */
.summary-grid {
  display: grid;
  grid-template-columns: minmax(0,.7fr) minmax(0,.7fr) minmax(0,1.6fr);
  /* The first two cards contain one number each; the text-heavy Groups card
     receives just over half of the available row width. */
  gap: 14px;
  margin-bottom: 16px;
}

.summary-card {
  border: 1px solid var(--border); background: var(--panel);
  border-radius: var(--radius); padding: 16px;
  box-shadow: var(--shadow-sm); display: flex; flex-direction: column;
  align-items: center; text-align: center;
}
.summary-card h4 {
  margin: 0 0 12px; font-size: 14px; color: var(--muted);
  text-transform: uppercase; letter-spacing: .08em; font-weight: 700;
  border-bottom: 1px solid var(--border); padding-bottom: 8px; width: 100%;
}
.summary-card-value {
  font-weight: 800; font-size: 36px; line-height: 1; color: var(--primary);
}
.summary-card--number { justify-content: flex-start; }
.summary-card--groups { align-items: stretch; text-align: left; }
.summary-card--groups h4 { text-align: center; }
.summary-groups-content {
  display: grid; grid-template-columns: auto minmax(0,1fr);
  align-items: start; gap: 16px; width: 100%;
}
.summary-group-list { display: flex; flex-wrap: wrap; gap: 6px; }
.summary-group-chip {
  display: inline-flex; align-items: center; min-width: 0;
  padding: 4px 8px; border-radius: 999px;
  background: #eff6ff; border: 1px solid #bfdbfe;
  color: #1e3a5f; font-size: 12px; line-height: 1.35;
}

.muted-sm { font-size: 13px; color: var(--muted); margin: 0; }   /* small, dimmed text -- used all over the app.js-generated HTML for placeholder/secondary text like "Loading…" */

/* ── Sensor detail ─────────────────────────────────────────────── */
/* No matching ".sensor-summary"/".detail-table" elements currently exist
   in index.html -- appears to be leftover from an earlier version of the
   Data Summary page before it was redesigned into the current
   ".profile-*" section styles further down this file. */
.sensor-summary {
  background: var(--panel); border-radius: var(--radius);
  padding: 18px; margin-bottom: 16px;
  box-shadow: var(--shadow-sm); border-left: 4px solid var(--primary);
}
.sensor-summary h4 { font-weight: 700; font-size: 15px; margin-bottom: 8px; }

.detail-table { width: 100%; border-collapse: collapse; font-size: 13px; margin-top: 10px; }
.detail-table td { padding: 4px 8px 4px 0; vertical-align: top; line-height: 1.5; }
.detail-table td:first-child { width: 150px; color: var(--muted); font-weight: 600; white-space: nowrap; }

.type-badge { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 12px; font-weight: 600; margin-right: 4px; }
/* Its background/color/border are NOT set here -- they're computed
   dynamically per sensor type (Air/Water/Weather/etc.) and applied as an
   inline style wherever this class is used in app.js, based on TYPE_COLORS. */

.researcher-link {
  display: inline-flex; align-items: center;
  padding: 3px 10px; background: #eff6ff; color: #1e40af;
  border-radius: 5px; text-decoration: none; font-weight: 600; font-size: 13px;
  border: 1px solid #bfdbfe;
}
.researcher-link:hover { background: #dbeafe; }

/* ── Download panel ────────────────────────────────────────────── */
/* No matching ".download-panel" element currently exists in index.html --
   likely superseded by the ".dl-viz-*" download boxes further down. */
.download-panel {
  padding: 16px 18px; background: var(--panel);
  border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-sm); margin-bottom: 4px;
}
.download-panel h4 { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .07em; margin-bottom: 2px; }
.download-btns { display: flex; gap: 10px; flex-wrap: wrap; }

/* ── Next tab nav ──────────────────────────────────────────────── */
/* Leftover from the old tabbed-navigation design mentioned above ("Tab
   card" section) -- no matching elements in the current index.html. */
.next-tab-row { display: flex; justify-content: flex-end; margin-top: 14px; }
.next-tab-btn {
  padding: 8px 14px; border-radius: 8px; background: var(--panel);
  border: 1px solid var(--border); box-shadow: var(--shadow-sm);
  cursor: pointer; font-weight: 700; font-size: 13px; color: var(--text);
  transition: background .1s;
}
.next-tab-btn:hover { background: #f8fafc; border-color: rgba(37,99,235,.35); }

/* ── Buttons ───────────────────────────────────────────────────── */
/* The base .btn class defines shape/sizing/transitions shared by every
   button style; each .btn-* modifier below only sets colors -- always used
   together, e.g. class="btn btn-primary". */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 8px 16px; border-radius: 7px; font-size: 13px; font-weight: 600;
  cursor: pointer; border: 1px solid transparent; text-decoration: none;
  transition: background .15s, transform .1s;
}
/* Without this, a hidden .btn (e.g. #viz-reset-zoom, #viz-retry-catalog)
   stays visible: the browser's own [hidden]{display:none} is a user-agent
   rule, which the .btn rule above -- an ordinary author rule, even at equal
   specificity -- always outranks in the cascade. */
.btn[hidden] { display: none !important; }
.btn-outline { background: #e5e7eb; color: var(--text) !important; border-color: #d1d5db; }   /* !important needed since some .btn-outline usages are on <a> tags, whose default link color would otherwise win */
.btn-outline:hover { background: #d1d5db; border-color: #9ca3af; transform: translateY(-1px); }
.btn-primary { background: var(--primary); color: #fff !important; border-color: var(--primary); }
.btn-primary:hover { background: var(--primary-2); transform: translateY(-1px); }
.btn-grey { background: #6b7280; color: #fff !important; border-color: #6b7280; }
.btn-grey:hover { background: #4b5563; transform: translateY(-1px); }
.btn-light-green { background: #86efac; color: #14532d !important; border-color: #86efac; }   /* used specifically for the "Download Map View CSV" link on the landing page */
.btn-light-green:hover { background: #4ade80; border-color: #4ade80; transform: translateY(-1px); }

/* ── Visualization ─────────────────────────────────────────────── */
.viz-toggle-bar {
  /* No matching element currently in index.html -- appears to be a
     leftover control bar from an earlier iteration of this page. */
  display: flex; align-items: center; flex-wrap: wrap; gap: 12px;
  padding: 12px 16px; margin-bottom: 20px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
.viz-toggle-label { font-weight: 700; font-size: 14px; margin-right: 4px; }
.radio-lbl { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 500; cursor: pointer; }
.radio-lbl input { cursor: pointer; accent-color: var(--primary); }

.snapshot-card {
  /* One "card" holding a single pre-built dashboard chart -- used by
     every render*Chart() function in app.js (VisiblAir, Tree3, MeteoWind, etc.). */
  padding: 18px; background: var(--panel);
  border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
.snapshot-card h4 { font-weight: 700; margin-bottom: 2px; }

/* Data Visualization page's 3-column control layout: Sensor / Graph Archetype / Download. */
.builder-grid { display: grid; grid-template-columns: repeat(3,1fr); gap: 14px; margin-bottom: 14px; }
.builder-box {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px; background: var(--panel); box-shadow: var(--shadow-sm);
}
.builder-box h4 { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin-bottom: 12px; }

.visualization-heading { margin-bottom: 18px; }
.visualization-heading--with-action {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
}
.visualization-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14px; align-items: start; margin-bottom: 14px; }
.visualization-series-box, .visualization-options-box { min-width: 0; }
.visualization-box-heading { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; margin-bottom: 14px; }
.visualization-box-heading h4 { margin-bottom: 4px; }
.visualization-heading-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
.visualization-heading-actions [hidden] { display: none !important; }
.viz-axis-selection-card, .viz-option-section {
  border: 1px solid var(--border); border-radius: 8px; background: #f8fafc;
  padding: 12px;
}
.viz-axis-selection-card + .viz-axis-selection-card { margin-top: 12px; }
.viz-axis-selection-card > .field-lbl { margin-top: 10px; }
.viz-axis-selection-card > .muted-sm { margin-top: 8px; }
.viz-x-parameter-fields, .viz-options-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 10px;
}
.viz-x-parameter-fields { margin-top: 10px; }
.viz-x-parameter-fields[hidden] { display: none; }
.viz-options-grid { margin-top: 12px; }
.viz-option-section { display: flex; flex-direction: column; gap: 10px; }
.viz-option-section--download { background: #f5faf9; border-color: #c8ddd8; }
.viz-option-section .viz-appearance-grid { margin-top: 10px; }
.viz-series-list { display: flex; flex-direction: column; gap: 10px; }
.viz-series-row {
  display: grid; grid-template-columns: minmax(180px, 1.25fr) minmax(160px, 1fr) 90px auto;
  gap: 10px; align-items: end; padding: 12px; border: 1px solid var(--border);
  border-radius: 8px; background: var(--panel);
}
.viz-remove-series {
  border: 0; background: transparent; color: #b91c1c; padding: 9px 4px;
  font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
}
.viz-remove-series:hover { text-decoration: underline; }
/* "Graph options" — X Axis / Y Axis columns, each its own bordered card so
   the grouping reads clearly even though the Y Axis column is much shorter
   (see the HTML comment above .viz-axis-grid for why Y only holds Range). */
.viz-axis-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px; }
.viz-axis-col {
  border: 1px solid var(--border); border-radius: 8px; background: #f8fafc;
  padding: 12px; display: flex; flex-direction: column; gap: 10px;
}
.viz-axis-heading {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--primary-2);
}
.viz-axis-col .field-lbl { margin-top: 2px; }
.is-disabled { opacity: .55; }
.viz-custom-dates { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.viz-custom-dates[hidden] { display: none; }

.viz-appearance { margin-bottom: 4px; }
.viz-appearance-heading {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); margin-bottom: 10px;
}
.viz-appearance-grid { display: grid; grid-template-columns: minmax(150px, 1fr) auto auto auto; gap: 12px; align-items: end; }
.viz-toggle {
  display: flex; align-items: center; gap: 6px;
  font-size: 13px; font-weight: 600; color: var(--text);
  padding-bottom: 9px;   /* lines the checkbox+label baseline up with the chart-type <select> beside it, which sits under a .field-lbl */
  white-space: nowrap; cursor: pointer;
}
.viz-toggle input { accent-color: var(--primary); cursor: pointer; }
.visualization-note { margin: 14px 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
.visualization-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.viz-option-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start; margin-top: auto; padding-top: 4px; }
.viz-action-with-limit { display: flex; flex-wrap: wrap; gap: 7px; align-items: center; }
.viz-action-limit {
  display: inline-flex; align-items: center; min-height: 30px; padding: 4px 8px;
  border-radius: 999px; background: #e8eef5; color: #415269;
  font-size: 11px; font-weight: 700; line-height: 1.2;
}
.visualization-status { min-height: 20px; margin-top: 10px; color: var(--muted); font-size: 12px; }
.visualization-status.is-error { color: #b91c1c; }
.visualization-chart-panel { height: 520px; min-height: 520px; }
.visualization-chart-panel canvas { min-height: 0; }

/* Student Life Centre research workspace */
.slc-research-hero {
  display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(260px, .8fr);
  gap: 18px; align-items: stretch; margin-bottom: 18px; padding: 24px;
  border-radius: var(--radius); border: 1px solid #bddbd5;
  background: linear-gradient(135deg, #f1faf8 0%, #f8fbff 100%);
}
.slc-research-hero h2 { margin: 4px 0 9px; font-size: 27px; line-height: 1.2; }
.slc-research-hero p { margin: 0; color: var(--muted); line-height: 1.65; }
.slc-research-caution {
  padding: 16px; border-radius: 10px; border: 1px solid #f0c36a;
  background: #fff9e8; align-self: stretch;
}
.slc-research-caution strong { display: block; color: #7c4a03; margin-bottom: 5px; }
.slc-research-caution p { color: #714f1b; font-size: 13px; }
.slc-pathway {
  display: grid; grid-template-columns: 1fr auto 1fr auto 1fr;
  gap: 10px; align-items: center; margin-bottom: 18px;
}
.slc-pathway-card {
  display: flex; align-items: center; gap: 11px; min-height: 72px; padding: 13px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--panel);
  box-shadow: var(--shadow-sm);
}
.slc-pathway-card strong, .slc-pathway-card small { display: block; }
.slc-pathway-card small { margin-top: 3px; color: var(--muted); line-height: 1.35; }
.slc-pathway-step {
  display: grid; place-items: center; flex: 0 0 30px; width: 30px; height: 30px;
  border-radius: 50%; background: var(--primary); color: #fff; font-weight: 800;
}
.slc-pathway-arrow { color: var(--primary-2); font-size: 23px; font-weight: 800; }
.slc-mode-choice {
  margin-bottom: 18px;
  padding: 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
  box-shadow: var(--shadow-sm);
}
.slc-mode-choice h3 { margin: 4px 0 5px; font-size: 22px; }
.slc-mode-intro { margin: 0 0 16px; color: var(--muted); line-height: 1.5; }
.slc-mode-links {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.slc-mode-link {
  display: grid;
  gap: 7px;
  width: 100%;
  min-height: 154px;
  padding: 18px;
  border: 1px solid var(--border);
  border-radius: 11px;
  background: #f8fafc;
  color: var(--text);
  text-align: left;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.slc-mode-link:hover, .slc-mode-link:focus-visible {
  border-color: var(--primary);
  box-shadow: 0 5px 16px rgba(0, 90, 70, .13);
  transform: translateY(-1px);
  outline: none;
}
.slc-mode-link.is-selected {
  border-color: var(--primary);
  background: #eef8f5;
  box-shadow: 0 0 0 2px rgba(0, 107, 84, .12);
}
.slc-mode-link-kicker {
  color: var(--primary);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.slc-mode-link strong { font-size: 20px; }
.slc-mode-link small { color: var(--muted); font-size: 13px; line-height: 1.5; }
.slc-mode-link-action { align-self: end; color: var(--primary); font-size: 13px; font-weight: 700; }
.slc-guide {
  margin-bottom: 18px;
  padding: 22px;
  border: 1px solid #bddbd5;
  border-radius: var(--radius);
  background: #f7fbfa;
  box-shadow: var(--shadow-sm);
}
.slc-guide[hidden] { display: none; }
.slc-guide-heading {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  align-items: flex-start;
  margin-bottom: 16px;
}
.slc-guide-heading h3 { margin: 4px 0 5px; font-size: 22px; }
.slc-guide-heading p { margin: 0; color: var(--muted); line-height: 1.5; }
.slc-guide-questions {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.slc-guide-question {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  width: 100%;
  min-height: 90px;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel);
  color: var(--text);
  text-align: left;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.slc-guide-question:hover, .slc-guide-question:focus-visible {
  border-color: var(--primary);
  box-shadow: 0 4px 14px rgba(0, 90, 70, .12);
  transform: translateY(-1px);
  outline: none;
}
.slc-guide-question.is-selected {
  border-color: var(--primary);
  background: #eef8f5;
  box-shadow: 0 0 0 2px rgba(0, 107, 84, .12);
}
.slc-guide-question > span:last-child { display: grid; gap: 5px; }
.slc-guide-question strong { line-height: 1.35; }
.slc-guide-question small { color: var(--muted); line-height: 1.45; }
.slc-guide-number {
  display: grid;
  place-items: center;
  flex: 0 0 28px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: #e5f3ef;
  color: var(--primary);
  font-size: 12px;
  font-weight: 800;
}
.slc-guide-question.is-selected .slc-guide-number { background: var(--primary); color: #fff; }
.slc-guide-panel {
  display: grid;
  gap: 14px;
  margin-top: 16px;
  padding: 18px;
  border: 1px solid #9fcfc5;
  border-left: 5px solid var(--primary);
  border-radius: 10px;
  background: var(--panel);
}
.slc-guide-panel[hidden] { display: none; }
.slc-guide-kicker {
  color: var(--primary);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.slc-guide-panel h4 { margin: 4px 0 5px; font-size: 19px; }
.slc-guide-panel-main p, .slc-guide-advice p { margin: 0; line-height: 1.55; }
.slc-guide-panel-main p { color: var(--muted); }
.slc-guide-advice {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
.slc-guide-advice article {
  padding: 12px;
  border-radius: 8px;
  background: #f4f7f9;
}
.slc-guide-advice strong { display: block; margin-bottom: 4px; font-size: 12px; }
.slc-guide-advice p { color: var(--muted); font-size: 12px; }
.slc-guide-panel .btn { justify-self: start; }
.slc-advanced-menu {
  margin-bottom: 18px;
  padding: 22px;
  border: 1px solid #b7cee7;
  border-radius: var(--radius);
  background: #f7faff;
  box-shadow: var(--shadow-sm);
}
.slc-advanced-menu[hidden] { display: none; }
.slc-advanced-heading { margin-bottom: 16px; }
.slc-advanced-heading h3 { margin: 4px 0 5px; font-size: 22px; }
.slc-advanced-heading p { margin: 0; color: var(--muted); line-height: 1.5; }
.slc-advanced-options {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.slc-advanced-option {
  display: grid;
  gap: 5px;
  width: 100%;
  min-height: 92px;
  padding: 14px 15px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--panel);
  color: var(--text);
  text-align: left;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.slc-advanced-option:hover, .slc-advanced-option:focus-visible {
  border-color: #2364aa;
  box-shadow: 0 4px 14px rgba(35, 100, 170, .13);
  transform: translateY(-1px);
  outline: none;
}
.slc-advanced-option.is-selected {
  border-color: #2364aa;
  background: #edf5ff;
  box-shadow: 0 0 0 2px rgba(35, 100, 170, .12);
}
.slc-advanced-option strong { font-size: 15px; line-height: 1.35; }
.slc-advanced-option small { color: var(--muted); line-height: 1.45; }
.slc-advanced-status {
  margin-top: 16px;
  padding: 12px 14px;
  border-radius: 8px;
  background: #e8f3ff;
  color: #174f87;
  font-size: 13px;
  line-height: 1.5;
}
.slc-advanced-status[hidden] { display: none; }
.slc-guided-inline {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, .65fr);
  gap: 14px;
  margin: -4px 0 18px;
  padding: 14px 16px;
  border-radius: 9px;
  background: #eef8f5;
  border: 1px solid #bddbd5;
}
.slc-guided-inline strong { display: block; margin-bottom: 4px; color: #005c49; }
.slc-guided-inline p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
.slc-research-section[hidden] { display: none; }
.slc-research-section {
  margin-bottom: 18px; padding: 20px; border: 1px solid var(--border);
  border-radius: var(--radius); background: var(--panel); box-shadow: var(--shadow-sm);
}
.slc-section-heading {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 14px; margin-bottom: 15px;
}
.slc-section-heading h3 { margin: 0 0 4px; }
.slc-section-heading p { margin: 0; color: var(--muted); font-size: 13px; }
.slc-period-badge, .slc-provisional-badge {
  display: inline-flex; align-items: center; padding: 5px 9px; border-radius: 999px;
  font-size: 11px; font-weight: 700; white-space: nowrap;
}
.slc-period-badge { background: #e8f3ff; color: #174f87; }
.slc-provisional-badge { margin-top: 8px; background: #fff1cc; color: #7c4a03; }
.slc-coverage-grid {
  display: grid; grid-template-columns: repeat(5, minmax(150px, 1fr)); gap: 10px;
}
.slc-coverage-card {
  min-width: 0; padding: 13px; border: 1px solid var(--border);
  border-top: 4px solid var(--slc-accent, var(--primary)); border-radius: 9px;
  background: #fbfcfe;
}
.slc-coverage-card h4 { margin: 0 0 3px; font-size: 13px; }
.slc-coverage-card .slc-source-role { min-height: 32px; color: var(--muted); font-size: 11px; line-height: 1.4; }
.slc-coverage-value { margin: 10px 0 2px; font-size: 22px; font-weight: 800; }
.slc-coverage-card small { color: var(--muted); line-height: 1.45; }
.slc-quality-controls {
  display: grid; grid-template-columns: 170px 170px minmax(310px, 1fr);
  gap: 10px; align-items: end;
}
.slc-quality-rules {
  display: flex; flex-wrap: wrap; gap: 8px 16px; margin: 14px 0 4px;
  padding: 12px 14px; border: 1px solid var(--border); border-radius: 9px;
  background: #f8fafc;
}
.slc-quality-rules legend {
  padding: 0 5px; color: var(--muted); font-size: 11px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}
.slc-quality-rules label {
  display: inline-flex; align-items: center; gap: 6px; color: var(--text);
  font-size: 12px; cursor: pointer;
}
.slc-quality-rules input { accent-color: var(--primary); }
.slc-quality-summary {
  display: grid; grid-template-columns: repeat(5, minmax(130px, 1fr));
  gap: 8px; margin-bottom: 12px;
}
.slc-quality-summary article {
  padding: 10px 11px; border: 1px solid var(--border); border-radius: 8px;
  background: #f8fafc;
}
.slc-quality-summary strong { display: block; font-size: 18px; }
.slc-quality-summary span { color: var(--muted); font-size: 11px; }
.slc-quality-table-wrap {
  max-height: 430px; overflow: auto; border: 1px solid var(--border);
  border-radius: 8px;
}
.slc-quality-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.slc-quality-table th, .slc-quality-table td {
  padding: 9px 10px; border-bottom: 1px solid var(--border); text-align: left;
  vertical-align: top;
}
.slc-quality-table th {
  position: sticky; top: 0; z-index: 1; background: #f1f5f9;
  color: var(--muted); font-size: 11px; letter-spacing: .04em;
  text-transform: uppercase; white-space: nowrap;
}
.slc-quality-table tr:last-child td { border-bottom: 0; }
.slc-quality-badge {
  display: inline-block; margin: 1px 4px 1px 0; padding: 3px 6px;
  border-radius: 999px; background: #fff1cc; color: #7c4a03;
  font-size: 10px; font-weight: 700;
}
.slc-quality-decision { font-weight: 700; }
.slc-quality-decision.is-excluded { color: #b91c1c; }
.slc-quality-decision.is-included { color: #166534; }
.slc-controls {
  display: grid; grid-template-columns: minmax(230px, 1.4fr) 150px 150px minmax(210px, auto) auto auto;
  gap: 10px; align-items: end; margin-bottom: 8px;
}
.slc-background-toggle {
  display: flex; align-items: center; gap: 7px; min-height: 39px;
  padding: 0 10px; border: 1px solid var(--border); border-radius: 6px;
  font-size: 12px; font-weight: 600; cursor: pointer;
}
.slc-background-toggle input { accent-color: var(--primary); }
.slc-chart-panel { height: 480px; min-height: 480px; padding: 18px; }
.slc-chart-panel canvas { min-height: 0; }
.slc-interpretation-grid {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 11px;
  margin-top: 14px;
}
.slc-interpretation-grid article {
  padding: 13px; border-radius: 9px; border: 1px solid var(--border); background: #f8fafc;
}
.slc-interpretation-grid h4 { margin: 0 0 5px; font-size: 13px; }
.slc-interpretation-grid p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
.slc-analysis-controls {
  display: grid; grid-template-columns: repeat(4, minmax(150px, 1fr));
  gap: 10px; align-items: end;
}
.slc-analysis-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.slc-analysis-stats {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px; margin: 10px 0 14px;
}
.slc-analysis-stats article {
  padding: 12px 14px; border: 1px solid var(--border); border-radius: 9px;
  background: #f8fafc;
}
.slc-analysis-stats span {
  display: block; color: var(--muted); font-size: 11px; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase;
}
.slc-analysis-stats strong { display: block; margin-top: 4px; font-size: 22px; }
.slc-analysis-chart-grid {
  display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(320px, .8fr);
  gap: 12px;
}
.slc-analysis-chart-panel {
  height: 430px; min-height: 430px; padding: 15px;
  align-items: stretch; justify-content: flex-start;
}
.slc-analysis-chart-panel > div:first-child { margin-bottom: 8px; }
.slc-analysis-chart-panel h4 { margin: 0 0 3px; }
.slc-analysis-chart-panel canvas { min-height: 0; flex: 1 1 auto; }
.slc-analysis-note {
  margin-top: 12px; padding: 11px 13px; border-left: 4px solid #d99a00;
  border-radius: 6px; background: #fff9e8; color: #714f1b;
  font-size: 12px; line-height: 1.55;
}
.slc-wind-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 220px;
  gap: 14px;
  align-items: stretch;
  margin-top: 14px;
}
.slc-wind-chart-panel {
  min-height: 500px;
  display: grid;
  place-items: center;
  overflow: hidden;
}
.slc-wind-rose { display: block; width: 100%; max-width: 620px; height: auto; }
.slc-wind-grid-ring, .slc-wind-axis {
  fill: none;
  stroke: #d8e0e8;
  stroke-width: 1;
}
.slc-wind-axis { stroke-dasharray: 3 4; }
.slc-wind-grid-label {
  fill: var(--muted);
  font-size: 11px;
  text-anchor: start;
}
.slc-wind-direction-label {
  fill: var(--text);
  font-size: 14px;
  font-weight: 800;
  text-anchor: middle;
  dominant-baseline: middle;
}
.slc-wind-petal {
  stroke: #fff;
  stroke-width: 1.25;
  transition: opacity 0.15s ease;
}
.slc-wind-petal:hover { opacity: 0.78; }
.slc-wind-centre { fill: var(--text); }
.slc-wind-legend-panel {
  padding: 18px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--bg);
}
.slc-wind-legend-panel h4 { margin: 0 0 12px; }
.slc-wind-legend { display: grid; gap: 10px; margin-bottom: 16px; }
.slc-wind-legend-item {
  display: grid;
  grid-template-columns: 18px 1fr;
  align-items: center;
  gap: 8px;
  font-size: 12px;
}
.slc-wind-legend-item span {
  width: 18px;
  height: 18px;
  border-radius: 4px;
  background: var(--wind-colour);
  border: 1px solid rgba(0, 0, 0, 0.08);
}
.slc-weekly-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(360px, .8fr);
  gap: 12px;
  align-items: stretch;
}
.slc-weekly-panel {
  min-width: 0;
  padding: 15px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
  box-shadow: var(--shadow);
}
.slc-weekly-panel h4 { margin: 0 0 3px; }
.slc-weekly-grid-scroll {
  margin-top: 16px;
  padding-bottom: 5px;
  overflow-x: auto;
}
.slc-weekly-grid {
  display: grid;
  grid-template-columns: 62px repeat(24, minmax(25px, 1fr));
  gap: 3px;
  min-width: 730px;
}
.slc-weekly-corner, .slc-weekly-hour-label, .slc-weekly-day-label {
  display: grid;
  align-items: center;
  color: var(--muted);
  font-size: 10px;
  font-weight: 700;
}
.slc-weekly-hour-label { justify-items: center; }
.slc-weekly-day-label { justify-items: end; padding-right: 6px; }
.slc-weekly-cell {
  min-height: 31px;
  border: 1px solid rgba(15, 23, 42, .08);
  border-radius: 4px;
  background: var(--weekly-cell-colour);
}
.slc-weekly-cell.is-empty {
  border-color: #e2e8f0;
  background: repeating-linear-gradient(135deg, #f8fafc 0 4px, #eef2f6 4px 8px);
}
.slc-weekly-cell:hover, .slc-weekly-cell:focus { outline: 2px solid #d99a00; outline-offset: 1px; }
.slc-weekly-heatmap-legend {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  min-height: 25px;
  margin-top: 8px;
  color: var(--muted);
  font-size: 10px;
}
.slc-weekly-gradient {
  width: 120px;
  height: 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: linear-gradient(90deg, hsl(209 72% 94%), hsl(209 72% 42%));
}
.slc-weekly-profile-panel { height: 430px; min-height: 430px; }
.slc-event-controls { margin-bottom: 8px; }
.slc-event-list-panel {
  height: 430px; min-height: 430px; padding: 15px; overflow: hidden;
  border: 1px solid var(--border); border-radius: var(--radius); background: #f8fafc;
}
.slc-event-list-panel h4 { margin: 0 0 9px; }
.slc-event-list { display: grid; gap: 8px; max-height: 375px; overflow-y: auto; }
.slc-event-item {
  display: grid; gap: 3px; padding: 10px 11px; border: 1px solid var(--border);
  border-left: 4px solid #7B4DB2; border-radius: 7px; background: var(--panel);
}
.slc-event-item strong { font-size: 12px; }
.slc-event-item span { color: var(--text); font-size: 12px; font-weight: 600; }
.slc-event-item small { color: var(--muted); line-height: 1.4; }
.slc-observation-form {
  display: grid; grid-template-columns: repeat(4, minmax(150px, 1fr));
  gap: 10px; align-items: end;
}
.slc-observation-notes { grid-column: span 3; }
.slc-observation-notes textarea { resize: vertical; min-height: 70px; }
.slc-observation-table-wrap {
  margin-top: 14px; overflow-x: auto; border: 1px solid var(--border);
  border-radius: 8px;
}
.slc-observation-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.slc-observation-table th, .slc-observation-table td {
  padding: 9px 10px; border-bottom: 1px solid var(--border); text-align: left;
  vertical-align: top;
}
.slc-observation-table th {
  background: #f1f5f9; color: var(--muted); font-size: 11px;
  text-transform: uppercase; letter-spacing: .04em; white-space: nowrap;
}
.slc-observation-table tr:last-child td { border-bottom: 0; }

/* Bird-migration weather research workspace */
.bird-research-hero {
  margin-bottom: 18px;
  padding: 24px;
  border: 1px solid #c9ddd7;
  border-radius: 14px;
  background: linear-gradient(135deg, #f3faf7 0%, #f8fbff 58%, #f7f3fb 100%);
}
.bird-research-hero h2 { margin: 4px 0 9px; font-size: 28px; line-height: 1.2; }
.bird-research-hero p { margin: 0; color: var(--muted); line-height: 1.65; }
.bird-research-section {
  display: grid;
  gap: 15px;
  margin-bottom: 18px;
  padding: 20px;
  border: 1px solid var(--border);
  border-radius: 13px;
  background: #f8fafc;
}
.bird-section-heading, .bird-panel-heading, .bird-future-panel {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  align-items: flex-start;
}
.bird-section-heading h3, .bird-future-panel h3 { margin: 4px 0 5px; }
.bird-section-heading p, .bird-future-panel p { margin: 0; color: var(--muted); line-height: 1.5; }
.bird-controls {
  display: grid;
  grid-template-columns: minmax(220px, 1.25fr) repeat(2, minmax(155px, .7fr)) auto;
  gap: 10px;
  align-items: end;
}
.bird-preset-row { display: flex; flex-wrap: wrap; align-items: center; gap: 7px; color: var(--muted); font-size: 12px; }
.bird-preset {
  padding: 6px 10px;
  border: 1px solid #b8d5cd;
  border-radius: 999px;
  background: #fff;
  color: #005c49;
  cursor: pointer;
  font: inherit;
  font-weight: 700;
}
.bird-preset:hover, .bird-preset:focus-visible { border-color: var(--primary); background: #edf8f4; }
.bird-stat-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}
.bird-stat-grid article {
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 9px;
  background: #fff;
}
.bird-stat-grid span { display: block; min-height: 30px; color: var(--muted); font-size: 11px; line-height: 1.35; }
.bird-stat-grid strong { display: block; margin-top: 3px; font-size: 21px; }
.bird-panel {
  min-width: 0;
  padding: 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: #fff;
  box-shadow: var(--shadow);
}
.bird-panel h4 { margin: 0 0 4px; }
.bird-panel-heading { align-items: center; }
.bird-heat-legend { display: flex; flex: 0 0 auto; align-items: center; gap: 7px; min-height: 24px; color: var(--muted); font-size: 10px; }
.bird-heat-gradient {
  display: inline-block;
  width: 110px;
  height: 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: linear-gradient(90deg, hsl(168 55% 94%), hsl(168 58% 32%));
}
.bird-colour-controls {
  display: grid;
  grid-template-columns: repeat(2, minmax(210px, 1fr)) auto;
  gap: 14px;
  align-items: end;
  margin-top: 14px;
  padding: 12px 13px;
  border: 1px solid #d8e5e1;
  border-radius: 8px;
  background: #f5faf8;
}
.bird-colour-control { display: grid; gap: 7px; }
.bird-colour-control label { color: var(--text); font-size: 11px; font-weight: 700; }
.bird-colour-control output { color: #005c49; }
.bird-colour-control input[type="range"] { width: 100%; accent-color: var(--primary); cursor: pointer; }
.bird-colour-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.bird-colour-actions .btn { padding: 7px 10px; font-size: 11px; }
.bird-colour-note { margin: 7px 2px 0; color: var(--muted); font-size: 10px; line-height: 1.45; }
.bird-calendar {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 13px;
  margin-top: 13px;
}
.bird-month { padding: 11px; border: 1px solid var(--border); border-radius: 8px; background: #fbfcfd; }
.bird-month h5 { margin: 0 0 8px; font-size: 12px; }
.bird-month-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.bird-weekday { color: var(--muted); font-size: 9px; font-weight: 700; text-align: center; }
.bird-day-spacer { min-height: 25px; }
.bird-heat-cell {
  display: grid;
  min-height: 28px;
  place-items: center;
  border: 1px solid rgba(15, 23, 42, .08);
  border-radius: 4px;
  background: var(--bird-cell-colour);
  color: #10231f;
  font-size: 9px;
  font-weight: 700;
}
.bird-heat-cell.is-dark { color: #fff; }
.bird-heat-cell.is-empty {
  border-color: #dbe3e8;
  background: repeating-linear-gradient(135deg, #f8fafc 0 4px, #eef2f6 4px 8px);
  color: #64748b;
}
.bird-heat-cell:hover, .bird-heat-cell:focus { outline: 2px solid #d99a00; outline-offset: 1px; }
.bird-hour-scroll { margin-top: 13px; padding-bottom: 5px; overflow-x: auto; }
.bird-hour-heatmap {
  display: grid;
  grid-template-columns: 60px repeat(24, minmax(25px, 1fr));
  gap: 3px;
  min-width: 760px;
}
.bird-hour-label, .bird-month-label {
  display: grid;
  align-items: center;
  color: var(--muted);
  font-size: 9px;
  font-weight: 700;
}
.bird-hour-label { justify-items: center; }
.bird-month-label { justify-items: end; padding-right: 5px; }
.bird-wind-layout { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(280px, .65fr); gap: 12px; }
.bird-wind-bars { display: grid; gap: 8px; margin-top: 15px; }
.bird-wind-row { display: grid; grid-template-columns: 30px minmax(0, 1fr) 54px; gap: 8px; align-items: center; font-size: 11px; }
.bird-wind-track { height: 14px; overflow: hidden; border-radius: 999px; background: #edf2f4; }
.bird-wind-fill { height: 100%; border-radius: inherit; background: linear-gradient(90deg, #78c5b3, #006b54); }
.bird-interpretation-panel {
  padding: 16px;
  border: 1px solid #d9cbea;
  border-radius: 10px;
  background: #faf8fd;
}
.bird-interpretation-panel h4 { margin: 0 0 8px; }
.bird-interpretation-panel ul { margin: 0; padding-left: 18px; color: var(--muted); font-size: 12px; line-height: 1.55; }
.bird-future-panel {
  margin-bottom: 12px;
  padding: 19px 20px;
  border: 1px dashed #9bbeb5;
  border-radius: 12px;
  background: #f5faf8;
}
.bird-future-badge { flex: 0 0 auto; padding: 6px 10px; border-radius: 999px; background: #e8f3ef; color: #005c49; font-size: 11px; font-weight: 800; }
.bird-source-note { margin-bottom: 20px; color: var(--muted); font-size: 11px; line-height: 1.5; }

.time-range-bar {
  /* The date-range filter row below the chart on the Data Visualization page. */
  margin-top: 20px; padding-top: 16px;
  border-top: 1px solid var(--border);
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
  width: 100%;
}
.time-range-label {
  font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); flex: 0 0 auto;
}
.time-range-inputs { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* ESQ location summaries show up to nine measurements. Keep these charts
   compact enough to scan as a group instead of stacking full-width panels. */
.esq-chart-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}
.esq-chart-card {
  min-width: 0;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
  box-shadow: var(--shadow-sm);
}
.esq-chart-card h4 {
  min-height: 34px;
  margin: 0 0 8px;
  font-size: 13px;
  line-height: 1.3;
}
.esq-chart-canvas {
  position: relative;
  height: 220px;
  min-height: 220px;
}
.esq-chart-canvas canvas {
  width: 100% !important;
  height: 100% !important;
}

@media (max-width: 1100px) {
  .esq-chart-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 700px) {
  .esq-chart-grid { grid-template-columns: minmax(0, 1fr); }
  .esq-chart-canvas { height: 240px; min-height: 240px; }
}

.chart-panel {
  /* The large box holding the actual Chart.js canvas. */
  position: relative;   /* positioning anchor for .wind-legend-badge below, which floats in this box's top-right corner */
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--panel); padding: 24px; min-height: 460px;
  box-shadow: var(--shadow);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  width: 100%; box-sizing: border-box; overflow: hidden;
}

.wind-legend-badge {
  /* Small floating badge, top-right corner of .chart-panel -- only shown
     for the Campus MeteoWind wind rose chart (see buildWindRoseChart()/
     renderCustomChart() in app.js). */
  position: absolute; top: 16px; right: 16px; z-index: 2;   /* z-index:2 just needs to be above the chart canvas itself, which has no explicit z-index (so effectively 0/auto) */
  background: var(--panel); border: 1px solid var(--border); border-radius: 6px;
  padding: 8px 10px; font-size: 12px; box-shadow: 0 1px 4px rgba(0,0,0,.08);
}

.viz-reset-zoom-btn {
  /* Shown (via app.js, once a drag-to-zoom selection has been made on the
     Data Visualization chart) top-right of .chart-panel, same corner as
     .wind-legend-badge above but they never appear on the same chart. */
  position: absolute; top: 16px; right: 16px; z-index: 2;
  font-size: 12px; padding: 6px 12px; box-shadow: 0 1px 4px rgba(0,0,0,.08);
}
.viz-zoom-hint {
  /* Standing "you can drag this" cue -- sits in normal document flow above
     .chart-panel (not overlaid on the canvas, which risked sitting on top
     of Chart.js's own legend), shown/hidden alongside the chart canvas
     itself (see renderAlignedVisualization() in app.js), not tied to
     whether a zoom is currently applied like .viz-reset-zoom-btn is. */
  margin: 0 0 8px; font-size: 12px; color: var(--muted);
}
.wsl-title { font-weight: 600; margin-bottom: 4px; }
.wsl-item { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
.wsl-swatch { width: 12px; height: 12px; border-radius: 2px; display: inline-block; background: #3b82f6; }
.wsl-note { color: var(--muted); margin-top: 6px; white-space: nowrap; }

.form-select {
  /* Shared style for every <select>/<input> in the builder boxes above (sensor/metric/graph-type/scale dropdowns, date inputs, contact form fields, etc.). */
  width: 100%; padding: 6px 8px;
  border: 1px solid var(--border-2); border-radius: 6px;
  font-size: 13px; background: var(--panel); color: var(--text); cursor: pointer;
}
.form-select:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 2px rgba(59,130,246,.2); }

.field-lbl { display: block; font-size: 12px; font-weight: 600; color: var(--muted); margin-bottom: 4px; }

/* ── About ─────────────────────────────────────────────────────── */
/* Legacy ".about-card" (a centred single card) is unused now, but kept as
   a reference. The live "About INSPIRE" page (#page-about) uses the
   ".about-*" rules below, and reuses ".team-page-section" wrappers. */
.about-wrap { display: flex; justify-content: center; padding: 20px 0 10px; }
.about-card {
  max-width: 680px; width: 100%;
  padding: 28px 32px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  line-height: 1.8; font-size: 14px; color: var(--text);
}
.about-card a { color: var(--primary-2); font-weight: 600; text-decoration: none; }
.about-card a:hover { text-decoration: underline; }

/* Small blue all-caps label used to make a page's lead text stand out --
   started on the About INSPIRE page, reused anywhere else that wants the
   same treatment (e.g. the Blog page intro). */
.page-eyebrow {
  font-size: 13px; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--primary); margin-bottom: 8px;
}

/* About INSPIRE — mission block */
.about-intro { line-height: 1.65; }
.about-headline { font-size: 20px; font-weight: 700; color: var(--text); margin: 0 0 16px; }
.about-lead { font-size: 16px; color: var(--text); margin: 0 0 14px; }
.about-body { font-size: 14px; color: var(--muted); margin: 0 0 12px; }
.about-list { padding-left: 20px; }
.about-list li { margin-bottom: 6px; }

/* About INSPIRE — Our Values */
.about-value-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 16px;
}
.about-value-card {
  border: 1px solid var(--border); background: var(--bg);
  border-radius: var(--radius); padding: 18px;
  border-top: 3px solid var(--primary);
  border-bottom: 3px solid var(--primary);
}
.about-value-name { font-size: 15px; font-weight: 700; color: var(--text); margin: 0 0 8px; }
.about-value-body { font-size: 13px; color: var(--muted); line-height: 1.6; margin: 0; }

/* About INSPIRE — stat row */
.about-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 14px;
  margin-bottom: 18px;
}
.about-stat {
  border: 1px solid var(--border); background: var(--bg);
  border-radius: var(--radius); padding: 18px 16px; text-align: center;
}
.about-stat-value { font-size: 32px; font-weight: 800; line-height: 1; color: var(--primary); }
.about-stat-label {
  margin-top: 8px; font-size: 12px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
}
.about-cities {
  font-size: 14px; color: var(--muted); line-height: 1.6;
  background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 12px 16px; margin-bottom: 24px;
}
.about-subheading {
  font-size: 15px; font-weight: 700; color: var(--text);
  margin: 0 0 14px; text-transform: uppercase; letter-spacing: .06em;
}

/* About INSPIRE — per-lab breakdown bars */
.about-cat-breakdown { display: flex; flex-direction: column; gap: 10px; }
.about-cat-row { display: grid; grid-template-columns: 120px 1fr auto; align-items: center; gap: 12px; }
.about-cat-name { font-size: 13px; font-weight: 700; letter-spacing: .04em; color: var(--text); }
.about-cat-track { height: 12px; background: var(--border); border-radius: 999px; overflow: hidden; }
.about-cat-fill { display: block; height: 100%; border-radius: 999px; min-width: 2px; transition: width .4s ease; }
.about-cat-count { font-size: 13px; font-weight: 700; color: var(--text); white-space: nowrap; }
.about-cat-unit { font-weight: 500; color: var(--muted); }

/* About INSPIRE — Lab definition cards */
.about-lab-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px;
}
.about-lab-card {
  border: 1px solid var(--border); background: var(--bg);
  border-radius: var(--radius); padding: 18px;
}
.about-lab-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.about-lab-dot { width: 14px; height: 14px; border-radius: 50%; flex: 0 0 auto; }
.about-lab-name { font-size: 15px; font-weight: 700; color: var(--text); margin: 0; }
.about-lab-focus { font-size: 13px; color: var(--muted); line-height: 1.55; margin: 0; }

/* About INSPIRE — Funding Partners (one card per partner, logo once) */
.about-funder-grid {
  display: grid;
  /* Wide cards: only two per row on a full-width section, one per row once
     the viewport is narrower, so the funded-item lines rarely wrap. */
  grid-template-columns: repeat(auto-fill, minmax(460px, 1fr));
  gap: 16px;
}
@media (max-width: 560px) {
  .about-funder-grid { grid-template-columns: 1fr; }
}
.about-funder-card {
  display: flex; gap: 16px; align-items: flex-start;
  border: 1px solid var(--border); background: var(--bg);
  border-radius: var(--radius); padding: 18px;
}
.about-funder-logo {
  flex: 0 0 132px; width: 132px; height: 132px;
  display: flex; align-items: center; justify-content: center;
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 12px;
}
.about-funder-logo img { max-width: 100%; max-height: 100%; object-fit: contain; }
.about-funder-logo--placeholder {
  border-style: dashed; color: var(--muted);
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .06em;
}
.about-funder-body { min-width: 0; }
.about-funder-name { font-size: 15px; font-weight: 700; color: var(--text); margin: 2px 0 10px; }
.about-funder-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.about-funder-items li { font-size: 13px; color: var(--text); line-height: 1.5; }
.about-funder-year {
  display: inline-block; margin-right: 8px; min-width: 62px;
  font-size: 12px; font-weight: 700; color: var(--muted);
}

@media (max-width: 480px) {
  .about-funder-card { flex-direction: column; align-items: center; text-align: center; }
  .about-funder-items { align-items: center; }
}

/* About INSPIRE — plain data table (Our Own Initiatives) */
.about-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.about-table th, .about-table td {
  text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.about-table th {
  font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--muted); font-weight: 700;
}
.about-table td { color: var(--text); }
.about-link-btn { font-size: 12px; padding: 4px 12px; }
.about-inline-link {
  background: none; border: none; padding: 0; cursor: pointer;
  color: var(--primary-2); font-weight: 600; font-size: inherit; font-family: inherit;
  text-decoration: underline;
}

@media (max-width: 700px) {
  .about-cat-row { grid-template-columns: 88px 1fr auto; gap: 8px; }
  .about-cat-name { font-size: 12px; }
}

/* ── INSPIRE Communities — link tiles ──────────────────────────── */
.community-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 18px;
}
.community-tile {
  display: flex; flex-direction: column; gap: 6px;
  padding: 22px 20px;
  background: var(--bg);
  border: 1px solid var(--border-2);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--text);
  transition: box-shadow .18s, border-color .18s, transform .12s;
}
.community-tile:hover {
  border-color: var(--primary);
  box-shadow: 0 4px 16px rgba(59,130,246,.25);
  transform: translateY(-2px);
}
.community-tile-name { font-size: 17px; font-weight: 700; color: var(--text); }
.community-tile-note { font-size: 13px; color: var(--muted); }
.community-tile-cta {
  margin-top: 6px; font-size: 13px; font-weight: 600; color: var(--primary-2);
}
/* Placeholder tiles for communities that don't have a site yet. */
.community-tile--soon { opacity: .6; cursor: default; }
.community-tile--soon:hover {
  border-color: var(--border-2); box-shadow: none; transform: none;
}
.community-tile--soon .community-tile-cta { color: var(--muted); }

/* "Build an INSPIRE Community" invitation tile -- sits in the grid
   alongside real community tiles, but a dashed blue border and tinted
   background mark it as "add yours" rather than an existing site. */
.community-tile--cta {
  background: rgba(59,130,246,.06);
  border: 2px dashed var(--primary);
}
.community-tile--cta:hover {
  background: rgba(59,130,246,.12);
  border-color: var(--primary-2);
  border-style: dashed;
}
.community-tile--cta .community-tile-name { color: var(--primary-2); }

/* ── Blog ─────────────────────────────────────────────────────── */

/* Topic filter pills -- same pill language as the header nav
   (.app-nav-link), scaled down. filterBlogPosts() in app.js toggles
   "active" here and shows/hides matching cards in #blog-list; the pinned
   Welcome post below is unaffected by this filter. */
.blog-topic-bar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 10px; }
.blog-topic-pill {
  background: var(--bg); border: 2px solid var(--border-2); cursor: pointer;
  font-size: 13px; font-weight: 600; color: var(--text); font-family: inherit;
  padding: 6px 14px; border-radius: 999px;
  transition: background .18s, color .18s, border-color .18s;
}
.blog-topic-pill:hover { border-color: var(--primary); }
.blog-topic-pill.active { background: var(--primary); color: #fff; border-color: var(--primary); }
/* One-line blurb for whichever pill is selected -- filterBlogPosts() in
   app.js fills this in from that pill's data-blog-desc and toggles the
   "hidden" attribute; "All" has no data-blog-desc, so it stays hidden. */
.blog-topic-desc { font-size: 14px; font-style: italic; color: var(--muted); margin: 0 0 24px; }

/* Pinned "Welcome" post -- accent top border sets it apart from the
   "Latest Posts" cards below. */
.blog-welcome-section { margin-bottom: 36px; }
.blog-post--welcome {
  border: 1px solid var(--border); background: var(--bg);
  border-radius: var(--radius); padding: 28px 32px;
  border-top: 3px solid var(--primary);
}
.blog-welcome-section .blog-post-title { font-size: 20px; }

.blog-latest-heading {
  font-size: 15px; font-weight: 700; color: var(--text);
  margin: 0 0 16px; text-transform: uppercase; letter-spacing: .06em;
}

/* "Latest Posts" grid -- multiple columns on wide screens, collapsing to one
   as space runs out. Each .blog-post is a self-contained card (see the
   template comment above #blog-list in index.html to add one). */
.blog-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
  gap: 20px;
}
.blog-empty {
  grid-column: 1 / -1;
  font-size: 14px; color: var(--muted);
  padding: 24px; text-align: center;
  background: var(--bg); border: 1px dashed var(--border-2); border-radius: var(--radius);
}
/* Whole tile shifts colour on hover -- a lighter "lift" (background moves
   from --bg to --panel, border/shadow pick up the brand blue) that signals
   the card holds a "Read full post" toggle, without implying the tile
   itself is one big link. */
.blog-post {
  border: 1px solid var(--border); background: var(--bg); border-radius: var(--radius); padding: 20px;
  transition: background .18s, border-color .18s, box-shadow .18s, transform .12s;
}
.blog-post:hover {
  background: var(--panel);
  border-color: var(--primary);
  box-shadow: var(--shadow);
  transform: translateY(-2px);
}
/* Wraps one .blog-post-tag span per topic a post is tagged with -- a post
   can belong to more than one (see the template comment above #blog-list in
   index.html). */
.blog-post-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.blog-post-tag {
  display: inline-block; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em;
  padding: 3px 10px; border-radius: 999px;
}
/* Tag colours reuse hues already used elsewhere on the site (BUILD/SWIM/MOVE
   in TYPE_COLORS + the About page Lab dots) so the blog stays visually tied
   to the rest of DataHub. Add a matching rule here for any new topic pill. */
.blog-post-tag--updates           { background: rgba(59,130,246,.14); color: var(--primary-2); }
.blog-post-tag--research          { background: rgba(35,100,170,.14); color: #2364AA; }
.blog-post-tag--community         { background: rgba(216,95,50,.14); color: #D85F32; }
.blog-post-tag--inspired-thoughts { background: rgba(123,77,178,.14); color: #7B4DB2; }

.blog-post-title { font-size: 17px; font-weight: 700; color: var(--text); margin: 0 0 6px; }
.blog-post-meta { font-size: 13px; color: var(--muted); margin-bottom: 12px; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; }
/* One pill per author, generated by renderBlogAuthorPills() in app.js from
   the .blog-post-authors[data-authors] span -- clicking jumps to and
   highlights that person on the Our Team & Contact page (goToTeamMember()). */
.blog-post-authors { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.blog-author-pill {
  display: inline-block; font: inherit; font-size: 12px; font-weight: 600;
  background: var(--bg); border: 1px solid var(--border-2); border-radius: 999px;
  padding: 1px 9px; color: var(--primary-2); cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.blog-author-pill:hover { background: var(--primary); border-color: var(--primary); color: #fff; }
.blog-post-excerpt { font-size: 14px; color: var(--muted); line-height: 1.6; margin: 0 0 12px; }
.blog-post-body { font-size: 14px; color: var(--text); line-height: 1.7; }
.blog-post-body p { margin: 0 0 12px; }
.blog-post-body p:last-child { margin-bottom: 0; }
.blog-post-body a { color: var(--primary-2); font-weight: 600; text-decoration: none; }
.blog-post-body a:hover { text-decoration: underline; }
.blog-post-body img { border-radius: var(--radius); margin: 8px 0; }
.blog-post-toggle {
  background: none; border: none; padding: 0; margin-top: 4px;
  color: var(--primary-2); font-weight: 600; font-size: 13px; cursor: pointer;
  font-family: inherit;
}
.blog-post-toggle:hover { text-decoration: underline; }

@media (max-width: 560px) {
  .blog-post--welcome { padding: 22px 20px; }
}

/* ── Footer ────────────────────────────────────────────────────── */
/* Note: this header comment is a leftover/misplaced label -- the rules
   immediately below it are actually the header NAV styles, not footer
   styles. The real ".app-footer" rules are further down this file, under
   their own (correctly labeled) "── Footer ──" section. */
/* ── Header nav ─────────────────────────────────────────────────── */
.app-nav {
  /* The pill-shaped nav buttons, top-right of the header. */
  margin-left: auto;   /* pushes this whole nav group as far right as possible within the flex header, without needing explicit positioning */
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: 6px;
  padding-right: 0;
}
.app-nav-link {
  background: var(--bg);
  border: 2px solid var(--border-2);
  cursor: pointer;
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  padding: 8px 14px;
  border-radius: 999px;   /* fully rounded pill shape */
  transition: background .18s, color .18s, border-color .18s, box-shadow .18s, transform .12s;
  white-space: nowrap;
  letter-spacing: 0.01em;
}
.app-nav-link:hover {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
  box-shadow: 0 4px 16px rgba(59,130,246,0.4);
  transform: translateY(-1px);
}
.app-nav-link.active {
  /* Same filled-blue look as :hover, but without the shadow/lift, so the
     "currently on this page" state reads as steady/settled rather than
     mid-hover-animation. */
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
  box-shadow: 0 2px 10px rgba(59,130,246,0.3);
}

/* ── Team & Contact page ────────────────────────────────────────── */
.team-page-section {
  /* Wraps each of the 3 sub-sections on page 4: Contact Us, Our Team, Collaborators. */
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 32px 36px;
  margin-bottom: 24px;
}
.team-page-heading {
  font-size: 22px;
  font-weight: 700;
  color: var(--text);
  margin-bottom: 20px;
  padding-bottom: 12px;
  border-bottom: 2px solid var(--border);
}
/* One-line lead paragraph for pages whose page-nav-row title already says
   the page name (Blog, INSPIRE Communities, ...) -- sized above
   .muted-sm fine print so the page doesn't open on a second, redundant
   repeat of its own title. */
.page-tagline { font-size: 16px; font-weight: 400; color: var(--text); line-height: 1.5; margin: 0; }

/* Contact form */
.contact-form { max-width: 680px; }   /* keeps the form from stretching uncomfortably wide on large screens */
.data-contribution-card {
  max-width: 880px;
  margin: 0 0 28px;
  padding: 20px 22px;
  border: 1px solid #bfdbfe;
  border-radius: 10px;
  background: #eff6ff;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}
.data-contribution-card h3 { margin: 0 0 6px; color: var(--text); font-size: 17px; }
.data-contribution-card p { margin: 0; color: var(--muted); font-size: 14px; line-height: 1.55; }
.data-contribution-button { flex-shrink: 0; white-space: nowrap; }
.contact-row { display: flex; gap: 16px; }   /* side-by-side Name/Email fields */
.contact-row .contact-field { flex: 1; }   /* the two fields inside a .contact-row split the width evenly */
.contact-field { display: flex; flex-direction: column; }
.contact-label { font-size: 13px; font-weight: 600; color: var(--text); margin-bottom: 6px; }
.contact-textarea { resize: vertical; min-height: 140px; font-family: inherit; }   /* font-family:inherit stops the textarea from falling back to the browser's default monospace font, matching the rest of the page instead */

/* Team cards */
.team-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));   /* fits as many 160px-minimum columns as will comfortably fit the container's width, wrapping to new rows automatically -- no fixed column count needed */
  gap: 20px;
}
.team-card {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px 16px;
  text-align: center;
  transition: box-shadow .18s;
}
.team-card:hover { box-shadow: var(--shadow); }
/* Briefly applied by goToTeamMember() in app.js (added via a blog post's
   author pill) to draw the eye to the card it just scrolled to -- removed
   again a couple seconds later, it isn't a persistent state. */
.team-card--highlight { animation: team-card-pulse 1.8s ease-out; }
@keyframes team-card-pulse {
  0% { box-shadow: 0 0 0 5px rgba(59,130,246,.4); }
  100% { box-shadow: 0 0 0 0 rgba(59,130,246,0); }
}
.team-avatar {
  /* The circular "initials" badge (e.g. "MZ") shown on each team card --
     just colored/shaped CSS, no actual image. */
  width: 64px; height: 64px;
  border-radius: 50%;
  background: var(--primary);
  color: #fff;
  font-size: 20px;
  font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto 14px;   /* horizontally centers the circle within its card */
}
.team-name { font-size: 15px; font-weight: 700; color: var(--text); margin-bottom: 4px; }
.team-role { font-size: 13px; color: var(--primary); font-weight: 600; margin-bottom: 2px; }
.team-dept { font-size: 12px; color: var(--muted); }
.team-link {
  display: inline-block; margin-top: 8px;
  font-size: 12px; font-weight: 600; color: var(--primary-2); text-decoration: none;
}
.team-link:hover { text-decoration: underline; }

/* Collaborator logos */
.collab-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  align-items: center;
}
.collab-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px 32px;
  transition: box-shadow .18s;
}
.collab-card:hover { box-shadow: var(--shadow); }
.collab-logo { max-height: 120px; max-width: 240px; object-fit: contain; }   /* object-fit:contain scales each differently-sized/shaped partner logo image down to fit this box uniformly without distorting its own aspect ratio */
.collab-logo-placeholder {
  /* No matching element in the current index.html (every collaborator
     card now has a real logo image) -- was presumably a fallback box shown
     before all 4 logo files were actually provided. */
  height: 60px; width: 140px;
  background: var(--border);
  border-radius: 6px;
  display: flex; align-items: center; justify-content: center;
  color: var(--muted); font-size: 13px; font-weight: 600;
}
.collab-name { font-size: 13px; font-weight: 600; color: var(--muted); }

/* Responsive tweaks for medium-narrow windows (e.g. a half-width desktop
   browser, or a tablet) -- fills the gap between the full desktop layout
   above and the more aggressive mobile rules below. */
@media (max-width: 1280px) {
  .app-header {
    min-height: 0;
    height: auto;
    flex-direction: column;
    flex-wrap: nowrap;
    justify-content: center;
    gap: 4px;
    padding: 6px 12px 8px;
  }
  .app-header img { height: 104px !important; }
  .app-nav {
    width: 100%;
    margin-left: 0;
    padding-right: 0;
    justify-content: center;
  }
}

@media (max-width: 1100px) {
  .visualization-layout { grid-template-columns: 1fr; }
}

/* Mobile-width layout adjustments. */
@media (max-width: 700px) {
  /* Header */
  .app-header { padding: 5px 10px 7px; gap: 3px; }
  .app-header img { height: 84px !important; }
  .app-nav { width: 100%; margin-left: 0; padding-right: 0; justify-content: center; gap: 4px; flex-wrap: wrap; }
  .app-nav-link { font-size: 13px; padding: 5px 9px; }

  /* Intro hero */
  .intro-top-layout { grid-template-columns: 1fr; }
  .intro-hero { flex-direction: column; gap: 16px; }
  .intro-jump-link { width: 100%; padding: 14px 16px; }

  /* Team & Contact page */
  .contact-row { flex-direction: column; }
  .data-contribution-card { align-items: stretch; flex-direction: column; gap: 16px; }
  .data-contribution-button { width: 100%; text-align: center; }
  .team-page-section { padding: 16px 12px; }
  .team-page-heading { font-size: 18px; }
  .team-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  .collab-grid { gap: 12px; }
  .collab-card { padding: 16px; }
  .collab-logo { max-height: 60px; max-width: 120px; }
}

/* ── Footer ─────────────────────────────────────────────────────── */
.app-footer {
  margin-top: 14px; padding: 14px 18px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius); text-align: center;
  font-size: 13px; color: var(--muted); line-height: 1.6;
}
.app-footer a { color: var(--primary-2); font-weight: 600; text-decoration: none; }
.app-footer a:hover { text-decoration: underline; }
.footer-data-contribution {
  margin-top: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
}
.app-footer .footer-data-button {
  color: #fff;
  padding: 7px 14px;
  font-size: 13px;
}
.app-footer .footer-data-button:hover { color: #fff; text-decoration: none; }

/* ── Popup ─────────────────────────────────────────────────────── */
/* Styles the actual CONTENT shown inside a Leaflet map marker popup --
   built as an HTML string by popupHtml() in app.js. The popup's own
   wrapper/chrome (the white bubble shape itself) is styled separately in
   popup.css, not here. */
.popup-table { font-size: 12px; min-width: 190px; border-collapse: collapse; color: #0f172a; }
.popup-table td { padding: 3px 6px; vertical-align: top; line-height: 1.4; }
.popup-table td:first-child {
  background: #f1f5f9;
  color: #475569;
  font-weight: 600;
  white-space: nowrap;
}   /* the label column (e.g. "Name", "Location") */


.multi-sensor-row {
  /* One row in the "multiple sensors selected, pick one" list on the Data Summary page. */
  display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; margin-bottom: 8px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius);
}
.multi-sensor-label { flex: 1; font-weight: 600; font-size: 14px; }
.btn-sm { padding: 4px 12px; font-size: 12px; }   /* smaller variant, combined with a .btn-* color class, e.g. class="btn btn-outline btn-sm" */

/* ── Data Summary profile page ─────────────────────────────────── */
.summary-empty {
  /* The "Select a sensor…" placeholder message shown before any sensor is chosen. */
  padding: 48px 24px; text-align: center; color: var(--muted);
  background: var(--panel); border: 2px dashed var(--border-2);
  border-radius: var(--radius); margin-bottom: 16px; font-size: 14px;
}

.profile-header {
  /* No matching element in the current index.html -- the sensor name is
     rendered as a plain <h2 id="profile-name"> instead now, without this
     dedicated header box wrapper. */
  padding: 20px 24px; margin-bottom: 14px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius); border-left: 5px solid var(--primary);
  box-shadow: var(--shadow-sm);
}
.profile-header h2 { font-size: 22px; font-weight: 800; margin: 0; }

.profile-section {
  /* Each labeled box on the sensor profile page: Sensor Information,
     Research Group Contact, Pre-Processed Dashboards, Data Visualization
     and Downloader, Data Upload. */
  padding: 16px 20px; margin-bottom: 14px;
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
}
.profile-section-title {
  font-size: 14px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .07em; color: var(--text);
  margin-bottom: 12px; padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 8px;
}

.profile-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.profile-table td { padding: 5px 8px 5px 0; vertical-align: top; line-height: 1.6; }
.profile-tkey { width: 160px; color: var(--muted); font-weight: 600; white-space: nowrap; }   /* fixed-width label column so every row's value column lines up vertically */
.profile-disclosure summary {
  width: fit-content;
  color: var(--primary);
  font-weight: 600;
  cursor: pointer;
}
.profile-disclosure summary:hover { text-decoration: underline; }
.profile-disclosure summary:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 2px;
}
.profile-disclosure[open] summary { margin-bottom: 6px; }
.profile-disclosure-content {
  padding: 7px 10px;
  background: #f8fafc;
  border-left: 3px solid var(--border-2);
  border-radius: 0 4px 4px 0;
  white-space: pre-line;
}

.profile-btns { display: flex; gap: 10px; flex-wrap: wrap; }

.dl-viz-grid {
  /* The standard summary's three download choices. Citizen-science summary
     layouts use separate classes and are unaffected by these rules. */
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.dl-viz-box {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 12px; background: var(--bg);
}
.dl-viz-box-title {
  font-weight: 700; font-size: 13px; color: var(--text);
}
.dl-viz-desc {
  font-size: 12px; color: var(--muted); margin: 0; line-height: 1.45;
}
.dl-viz-box--quick {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "title action" "description action";
  column-gap: 14px; row-gap: 3px; align-items: center;
}
.dl-viz-box--quick .dl-viz-box-title { grid-area: title; }
.dl-viz-box--quick .dl-viz-desc { grid-area: description; }
.dl-viz-box--quick .btn { grid-area: action; white-space: nowrap; }
.dl-viz-box--custom {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(170px, .8fr) minmax(280px, 1.2fr) minmax(190px, auto);
  grid-template-areas: "copy dates actions";
  gap: 16px; align-items: center;
}
.dl-viz-custom-copy { grid-area: copy; display: grid; gap: 3px; }
.dl-viz-custom-actions { grid-area: actions; display: grid; gap: 4px; }
.dl-viz-custom-actions .btn { width: 100%; box-sizing: border-box; }
.summary-date-range {
  grid-area: dates;
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: 7px 8px; align-items: center;
}
.summary-date-range label { font-size: 12px; font-weight: 600; color: var(--muted); }
.summary-date-range input {
  width: 100%; min-width: 0; box-sizing: border-box;
  padding: 7px 8px; border: 1px solid var(--border-2);
  border-radius: 6px; background: var(--panel); color: var(--text);
}
#summary-download-status:not(:empty) { min-height: 16px; }

@media (max-width: 850px) {
  .dl-viz-grid { grid-template-columns: 1fr; }
  .dl-viz-box--custom {
    grid-column: auto;
    grid-template-columns: minmax(0, 1fr) minmax(190px, .7fr);
    grid-template-areas: "copy copy" "dates actions";
    gap: 10px 14px;
  }
}

/* ── Flood-report citizen-science summaries ──────────────────── */
.flood-program-intro h2 { margin: 0 0 8px; }
.flood-program-intro .muted-sm { max-width: 850px; line-height: 1.6; }
.flood-summary-grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px; margin-bottom: 16px;
}
.flood-summary-card {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--panel); padding: 14px; text-align: center;
  box-shadow: var(--shadow-sm);
}
.flood-summary-card-label {
  color: var(--muted); font-size: 11px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase;
}
.flood-summary-card-value {
  color: #B3261E; font-size: 26px; font-weight: 800; margin-top: 5px;
}
.flood-summary-card-value.flood-date-value { font-size: 17px; line-height: 1.35; }
.flood-breakdown-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px;
}
.flood-breakdown-panel {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--bg); padding: 12px;
}
.flood-breakdown-panel h3 { font-size: 14px; margin: 0 0 10px; }
.flood-breakdown-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px; padding: 6px 0; border-top: 1px solid var(--border);
  font-size: 12px;
}
.flood-breakdown-row:first-of-type { border-top: 0; }
.flood-breakdown-count { font-weight: 800; color: #B3261E; }
.flood-filter-bar {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px; margin-bottom: 8px;
}
.flood-filter-bar label {
  display: grid; gap: 5px; color: var(--muted);
  font-size: 12px; font-weight: 700;
}
.flood-filter-status { min-height: 20px; margin-bottom: 8px; }
.flood-map {
  width: 100%; height: 360px; border: 1px solid var(--border);
  border-radius: var(--radius); overflow: hidden; margin-bottom: 14px;
}
.flood-report-gallery {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px;
}
.flood-report-card {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--panel); overflow: hidden; display: flex;
  flex-direction: column; min-width: 0;
}
.flood-report-card-image,
.flood-report-card-placeholder {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover; display: block;
  background: #e5e7eb;
}
.flood-report-card-placeholder {
  display: grid; place-items: center; color: var(--muted); font-size: 12px;
}
.flood-report-card-body {
  padding: 11px; display: flex; flex-direction: column; gap: 6px; flex: 1;
}
.flood-report-card-title { font-size: 14px; font-weight: 700; }
.flood-report-card-meta { color: var(--muted); font-size: 12px; line-height: 1.45; }
.flood-report-card .btn { margin-top: auto; width: 100%; box-sizing: border-box; }
.flood-back-button { margin-bottom: 12px; }
.flood-photo-gallery {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px;
}
.flood-photo-link {
  display: block; border-radius: 8px; overflow: hidden;
  border: 1px solid var(--border); background: var(--bg);
}
.flood-photo-link img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block;
  transition: transform .2s;
}
.flood-photo-link:hover img { transform: scale(1.02); }
.flood-detail-map { height: 320px; margin-bottom: 0; }

/* Bird-collision photographs may be sensitive. They begin blurred and can be
   revealed individually or together using the preference above the summary. */
.bird-photo-preference {
  margin-bottom: 16px;
  padding: 12px 14px;
  border: 1px solid #f0c36a;
  border-radius: var(--radius);
  background: #fff8e6;
}
.bird-photo-preference-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text);
  font-weight: 700;
  cursor: pointer;
}
.bird-photo-preference-toggle input {
  accent-color: #b3261e;
  cursor: pointer;
}
.bird-photo-preference p {
  margin: 5px 0 0 24px;
  color: #64748b;
  font-size: 12px;
  line-height: 1.5;
}
.bird-sensitive-photo {
  position: relative;
  overflow: hidden;
  background: #e2e8f0;
}
.bird-report-card-photo {
  width: 100%;
  aspect-ratio: 16 / 9;
}
.bird-report-card-photo .flood-report-card-image { height: 100%; }
.bird-sensitive-photo img {
  filter: blur(16px);
  transform: scale(1.08);
  transition: filter .2s, transform .2s;
}
.bird-photo-reveal {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 12px;
  border: 0;
  background: rgba(15, 23, 42, .58);
  color: #fff;
  text-align: center;
  font: inherit;
}
button.bird-photo-reveal { cursor: pointer; }
.bird-photo-reveal span { font-size: 13px; font-weight: 800; }
.bird-photo-reveal small { font-size: 11px; }
#bird-summary-profile.bird-photos-visible .bird-sensitive-photo img,
.bird-sensitive-photo.is-revealed img {
  filter: none;
  transform: none;
}
#bird-summary-profile.bird-photos-visible .bird-photo-reveal,
.bird-sensitive-photo.is-revealed .bird-photo-reveal {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.profile-restricted-badge {
  /* No matching element in the current index.html -- appears to be an
     unused "restricted access" indicator, possibly planned but never wired up. */
  background: #fef2f2; color: #b91c1c;
  border: 1px solid #fecaca; border-radius: 10px;
  padding: 1px 8px; font-size: 11px; font-weight: 700;
  text-transform: none; letter-spacing: 0;
}

.profile-contact-info { font-size: 13px; line-height: 2.2; }   /* generous line-height gives the stacked contact-name/email/group/website lines (see _renderProfile() in app.js) some breathing room */
.profile-contact-info a { color: var(--primary-2); font-weight: 600; text-decoration: none; }
.profile-contact-info a:hover { text-decoration: underline; }

/* Upload drop zone */
.upload-form { max-width: 520px; margin: 0 auto; text-align: center; }
.upload-drop {
  border: 2px dashed var(--border-2); border-radius: var(--radius);
  padding: 22px; text-align: center; font-size: 13px; color: var(--muted);
  background: #f8fafc; cursor: pointer;
  transition: border-color .15s, background .15s;
}
.upload-drop:hover { border-color: var(--primary); background: #eff6ff; color: var(--text); }
.upload-drop-active { border-color: var(--primary) !important; background: #eff6ff !important; color: var(--text) !important; }
.upload-mapping-grid { margin-top: 14px; text-align: left; }
.upload-mapping-row {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 10px; align-items: center; margin-top: 8px;
}
.upload-source-column { font-size: 12px; overflow-wrap: anywhere; color: var(--text); }
.upload-summary {
  margin-top: 12px; padding: 10px; border: 1px solid var(--border);
  border-radius: 6px; background: var(--bg); font-size: 12px;
}
/* .upload-drop-active is added/removed by JS during an actual
   drag-over-the-page action (see setupUpload() in app.js) -- !important is
   used here since this state needs to reliably win over the plain
   .upload-drop rule above regardless of selector order/specificity quirks. */

/* ── Mobile filter button (hidden on desktop) ──────────────────── */
/* No matching element in the current index.html -- the actual mobile
   equivalent is .map-panel-toggle (further up this file), not this class.
   Likely an earlier, since-replaced version of that same idea. */
.mobile-filter-btn {
  display: none;
  margin-left: auto;
  padding: 6px 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel);
  font-size: 13px; font-weight: 600;
  cursor: pointer; color: var(--text);
}


/* ── Responsive breakpoint ─────────────────────────────────────── */
/* The single main mobile breakpoint for the rest of the app's layout
   (separate from the Team & Contact page's own mobile rules defined
   earlier, inside the same @media (max-width: 700px) query up above --
   CSS allows multiple separate blocks targeting the same breakpoint). */
@media (max-width: 700px) {
  .mobile-filter-btn { display: flex; align-items: center; gap: 6px; }
  .app-main { padding: 10px; }
  .map-section-heading { flex-direction: column; align-items: stretch; gap: 10px; }
  .map-section-actions .btn { width: 100%; }
  .citizen-section { padding: 16px; }
  .citizen-initiative-grid { grid-template-columns: 1fr; }
  .citizen-initiative-actions { flex-direction: column; }
  .citizen-initiative-actions .btn { width: 100%; }
  .summary-grid { grid-template-columns: 1fr; }   /* 3 stat cards stack into a single column instead of staying side-by-side */
  .summary-groups-content { grid-template-columns: 1fr; gap: 10px; text-align: center; }
  .summary-group-list { justify-content: center; }
  .dl-viz-grid  { grid-template-columns: 1fr; }   /* download choices stack into a single column */
  .dl-viz-box--quick {
    grid-template-columns: 1fr;
    grid-template-areas: "title" "description" "action";
    gap: 5px;
  }
  .dl-viz-box--quick .btn { width: 100%; margin-top: 3px; }
  .dl-viz-box--custom {
    grid-template-columns: 1fr;
    grid-template-areas: "copy" "dates" "actions";
    gap: 9px;
  }
  .summary-date-range input { min-height: 42px; }
  .flood-summary-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .flood-breakdown-grid, .flood-filter-bar { grid-template-columns: 1fr; }
  .flood-report-gallery { grid-template-columns: 1fr; }
  .flood-photo-gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .flood-map { height: 280px; }
  .flood-detail-map { height: 250px; }
  .page-nav-row { flex-direction: column; gap: 8px; }
  .intro-actions { flex-direction: column; }   /* note: no ".intro-actions" element currently exists in index.html -- likely a stale selector from a since-renamed class (compare ".intro-hero-right", which holds the actual button today) */
  .builder-grid { grid-template-columns: 1fr; }   /* Data Visualization page's 3 control boxes stack vertically on mobile */
  .visualization-box-heading { flex-direction: column; }
  .visualization-heading-actions { width: 100%; }
  .visualization-box-heading .btn { width: 100%; }
  .viz-series-row { grid-template-columns: 1fr; }
  .viz-remove-series { justify-self: start; padding: 2px 0; }
  .viz-axis-grid, .viz-custom-dates, .viz-appearance-grid,
  .viz-x-parameter-fields, .viz-options-grid { grid-template-columns: 1fr; }
  .viz-toggle { padding-bottom: 0; }
  .visualization-actions .btn { width: 100%; }
  .viz-action-with-limit { align-items: stretch; }
  .viz-action-limit { justify-content: center; }
  .visualization-heading--with-action, .slc-section-heading { flex-direction: column; }
  .visualization-heading--with-action .btn { width: 100%; }
  .slc-research-hero { grid-template-columns: 1fr; padding: 17px; }
  .slc-research-hero h2 { font-size: 23px; }
  .slc-pathway { grid-template-columns: 1fr; }
  .slc-pathway-arrow { transform: rotate(90deg); justify-self: center; }
  .slc-mode-choice, .slc-guide { padding: 16px; }
  .slc-mode-links { grid-template-columns: 1fr; }
  .slc-guide-heading, .slc-guide-advice, .slc-guided-inline { grid-template-columns: 1fr; }
  .slc-guide-heading { display: grid; }
  .slc-guide-heading .btn, .slc-guide-panel .btn { width: 100%; }
  .slc-guide-questions, .slc-advanced-options { grid-template-columns: 1fr; }
  .slc-coverage-grid, .slc-interpretation-grid { grid-template-columns: 1fr; }
  .slc-controls { grid-template-columns: 1fr; }
  .slc-controls .btn { width: 100%; }
  .slc-chart-panel { height: 360px; min-height: 360px; padding: 10px; }
  .slc-quality-controls, .slc-analysis-controls, .slc-analysis-stats, .slc-analysis-chart-grid, .slc-observation-form, .slc-wind-layout, .slc-weekly-layout { grid-template-columns: 1fr; }
  .slc-quality-summary { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .slc-analysis-actions, .slc-analysis-actions .btn { width: 100%; }
  .slc-analysis-chart-panel { height: 360px; min-height: 360px; padding: 10px; }
  .slc-event-list-panel { height: auto; min-height: 0; }
  .slc-event-list { max-height: 320px; }
  .slc-wind-chart-panel { min-height: 360px; padding: 8px; }
  .slc-wind-legend-panel { padding: 14px; }
  .slc-observation-notes { grid-column: auto; }
  .bird-controls, .bird-stat-grid, .bird-wind-layout, .bird-colour-controls { grid-template-columns: 1fr; }
  .bird-research-hero { padding: 17px; }
  .bird-research-hero h2 { font-size: 23px; }
  .bird-section-heading, .bird-panel-heading, .bird-future-panel { flex-direction: column; }
  .bird-section-heading .btn, .bird-controls .btn { width: 100%; }
  .bird-calendar { grid-template-columns: 1fr; }
  .bird-colour-actions, .bird-colour-actions .btn { width: 100%; }
  .bird-future-badge { flex: auto; }
  .visualization-chart-panel { height: 360px; min-height: 360px; padding: 12px; }
  .chart-panel { min-height: 280px; }   /* shorter minimum chart height on small screens, vs. 460px on desktop */
  .prebuilt-card { min-height: 260px; }   /* note: no ".prebuilt-card" class exists elsewhere in this file -- the actual dashboard card class is ".snapshot-card" (defined above), so this specific rule currently has no effect */
  .sidebar { width: calc(100% - 20px); max-height: 55%; }   /* the floating filter panel widens to nearly the full screen width and shrinks its max height, since the small fixed 230px width from the desktop rule would be awkwardly narrow on a phone */
  .map-wrapper { height: 340px; }   /* smaller than the 460px desktop height so the map doesn't eat too much of a phone's vertical scroll space */
}
