/* === Variables === */
:root {
  --color-bg: #0f1117;
  --color-surface: #181a20;
  --color-text: #b0b4bf;
  --color-text-muted: #7a7f8e;
  --color-primary: #4f8cff;
  --color-primary-light: #1a2a44;
  --color-bezug: #4f8cff;
  --color-einspeisung: #facc15;
  --color-border: #23272f;
  --color-accent: #34d399;
  --color-glow: rgba(79, 140, 255, 0.15);
  --chart-height: 320px;
  --radius: 10px;
  --shadow: 0 1px 4px rgba(0,0,0,0.3);
  --shadow-lg: 0 4px 20px rgba(0,0,0,0.4);
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}

/* === Reset === */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html, body { height: 100%; font-family: var(--font); color: var(--color-text); background: var(--color-bg); }
body { display: flex; flex-direction: column; }

/* === Header === */
#header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 1.5rem;
  height: 52px;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  z-index: 1000;
}
.header-left { display: flex; align-items: center; gap: 0.5rem; }
.header-logo { height: 20px; width: auto; }
.header-logo--invert { filter: invert(1) brightness(1.8); }
.header-logo--maennedorf { height: 38px; }
.header-left h1 { font-size: 1rem; font-weight: 600; letter-spacing: 0.02em; }
.header-left h1.brand { font-size: 0; line-height: 0; margin: 0; display: flex; align-items: center; }
.brand-wordmark { height: 30px; width: auto; display: block; }
/* Commune lockup next to the FlexOps wordmark (tenant branding). Split mark +
   text: the emblem reads optically smaller than the letters at equal box height
   (the text SVG box includes ascenders), so the wappen box is a touch taller to
   match the text's cap-height — same calibration as the landing brandbar. */
.brand-div { width: 1px; height: 22px; background: var(--color-border); flex: 0 0 auto; }
.brand-mae { display: inline-flex; align-items: center; gap: 0.45rem; }
.brand-mae-text { height: 18px; width: auto; display: block; }
.brand-mae-mark { height: 25px; width: auto; display: block; }
.header-right { display: flex; gap: 0.5rem; }

/* === Buttons === */
.btn {
  padding: 0.35rem 0.9rem;
  border-radius: var(--radius);
  font-size: 0.8rem;
  font-weight: 500;
  cursor: pointer;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  transition: all 0.15s;
}
.btn:hover { background: var(--color-bg); border-color: var(--color-text-muted); }
.btn-primary { background: var(--color-primary); color: #0f1117; border-color: var(--color-primary); font-weight: 600; }
.btn-primary:hover { background: #3b7aff; box-shadow: 0 0 12px var(--color-glow); }
/* Active state lives in the design-polish block below (tinted, matches the pills). */

/* === Footer === */
#footer {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 24px;
  font-size: 0.6rem;
  color: var(--color-text-muted);
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
}
#footer a { color: var(--color-text-muted); text-decoration: none; }
#footer a:hover { color: var(--color-primary); text-decoration: underline; }

/* === Global Filter Panel === */
#filter-panel {
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  z-index: 999;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0 1.5rem;
}
#filter-pills-host { flex: 1 1 auto; min-width: 0; }
.view-context {
  flex: 0 0 auto;
  text-align: right;
  padding: 0.6rem 0;
  line-height: 1.25;
}
.view-context[hidden] { display: none; }
.view-context .vc-title { font-size: 1rem; font-weight: 600; color: var(--color-text); }
.view-context .vc-sub { font-size: 0.7rem; color: var(--color-text-muted); }

/* Data-quality round indicator (filter bar) + floating popup */
/* Indicator bubbles (Hinweise + Datenqualität) sit grouped just left of the
   view title; the last one keeps a gap before the title. */
.dq-indicator { position: relative; flex: 0 0 auto; }
.dq-indicator[hidden] { display: none; }
#view-context { margin-left: 0.9rem; }
.dq-dot-btn {
  width: 26px; height: 26px; border-radius: 50%;
  border: none; cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font); font-size: 0.72rem; font-weight: 700;
  font-variant-numeric: tabular-nums; color: #0f1117;
}
.dq-dot-btn--critical { background: #f87171; box-shadow: 0 0 8px rgba(248, 113, 113, 0.55); }
.dq-dot-btn--warning { background: #f59e0b; box-shadow: 0 0 8px rgba(245, 158, 11, 0.45); }
.dq-dot-btn--info { background: #60a5fa; box-shadow: 0 0 8px rgba(96, 165, 250, 0.45); }
.dq-item--static { cursor: default; }
.dq-item--static:hover { opacity: 1; }
.dq-popup {
  position: absolute; top: 100%; right: 0;
  width: 360px; max-height: 60vh; overflow-y: auto;
  margin-top: 6px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.5);
  padding: 0.7rem 0.8rem; z-index: 1200; text-align: left;
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
}
/* bridge the 6px gap so the popup stays open while the cursor crosses it */
.dq-popup::before { content: ''; position: absolute; top: -6px; left: 0; right: 0; height: 6px; }
.dq-indicator:hover .dq-popup,
.dq-indicator:focus-within .dq-popup { opacity: 1; visibility: visible; transform: translateY(0); }
.dq-popup-head {
  font-size: 0.8rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--color-text-muted); margin-bottom: 0.5rem;
}

/* Centered empty-state placeholder (comparison prompt, no-data analysis) */
.empty-state {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center; min-height: 55vh; gap: 0.6rem;
}
.empty-state-title { font-size: 1.4rem; font-weight: 600; color: var(--color-text); }
.empty-state-text { font-size: 0.9rem; color: var(--color-text-muted); max-width: 32ch; }
.filter-panel-inner {
  display: flex;
  gap: 2rem;
  /* Horizontal padding comes from #filter-panel (1.5rem) so the first pill lines
     up with the rail's 1.5rem gutter (search box / Verbrauch pill); only the
     vertical padding lives here. */
  padding: 0.6rem 0;
  align-items: flex-start;
}
.filter-group {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.filter-group-label {
  font-size: 0.6rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
}
.filter-pills {
  display: flex;
  gap: 0.25rem;
  flex-wrap: wrap;
}
.fp-pill {
  padding: 0.2rem 0.55rem;
  font-size: 0.7rem;
  border-radius: 10px;
  cursor: pointer;
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text-muted);
  font-family: var(--font);
  font-variant-numeric: tabular-nums;
  transition: all 0.15s;
}
.fp-pill:hover:not(.disabled) { border-color: var(--color-text-muted); color: var(--color-text); }
.fp-pill.active {
  color: var(--color-bezug);
  background: color-mix(in srgb, var(--color-bezug) 16%, transparent);
  border-color: color-mix(in srgb, var(--color-bezug) 55%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-bezug) 30%, transparent);
}
.fp-pill.disabled { opacity: 0.3; cursor: not-allowed; }

/* === Main Layout === */
#main {
  display: grid;
  grid-template-columns: 630px 1fr;
  flex: 1;
  min-height: 0;
}

/* === Left rail: building list + minimap === */
#left-rail {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--color-surface);
  border-right: 1px solid var(--color-border);
}
#building-list-panel {
  /* The rail splits 1:1 — list (search + sort + list) on top, minimap below,
     each taking half the rail height. Footer sits outside the rail. */
  flex: 1 1 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* 1.5rem horizontal inset so the search box, sort pills and list rows line up
     with the filter-bar pills (.filter-panel-inner) above them. */
  padding: 0.85rem 1.5rem 0.5rem;
  /* No transition: the list swaps instantly so the search box appears to stay
     put across view switches. Only the map (#minimap-panel) animates. */
}
.bl-search {
  width: 100%;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  color: var(--color-text);
  font-size: 0.8rem;
  padding: 0.45rem 0.6rem;
  margin-bottom: 0.6rem;
}
.bl-search:focus { outline: none; border-color: var(--color-primary); }
.bl-search::placeholder { color: var(--color-text-muted); }
#bl-sort { margin-bottom: 0.5rem; align-items: center; }
.bl-list {
  flex: 1 1 auto;
  min-height: 0;
  /* Rows stretch to share the available height, flowing down to the pager —
     no scrollbar (pagination caps the count at PAGE_SIZE). */
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding-right: 2px;
}
.bl-list .ranking-item { flex: 1 1 0; min-height: 0; max-height: 72px; }
.ranking-item--filler { cursor: default; pointer-events: none; border-bottom-color: transparent; }
.bl-pager {
  display: flex; align-items: center; justify-content: center; gap: 0.75rem;
  padding: 0.5rem 0 0.2rem; flex: 0 0 auto;
}
.bl-pager[hidden] { display: none; }
.bl-page-btn {
  width: 26px; height: 26px; border-radius: 50%;
  border: 1px solid var(--color-border); background: var(--color-bg);
  color: var(--color-text); cursor: pointer; font-size: 0.9rem; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  transition: all 0.15s;
}
.bl-page-btn:hover:not(:disabled) {
  color: var(--color-bezug);
  background: color-mix(in srgb, var(--color-bezug) 14%, transparent);
  border-color: color-mix(in srgb, var(--color-bezug) 55%, transparent);
}
.bl-page-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.bl-page-info { font-size: 0.72rem; color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
.bl-list::-webkit-scrollbar { width: 6px; }
.bl-list::-webkit-scrollbar-track { background: transparent; }
.bl-list::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 3px; }
.bl-empty { color: var(--color-text-muted); font-size: 0.75rem; padding: 0.5rem 0.2rem; }

#minimap-panel {
  /* Bottom half of the rail (#building-list-panel takes the top half). The map
     reads as a card: inset from the rail edges with a bottom gap so its bottom
     aligns with the content's last graph tile (#sidebar has the same 1.5rem
     padding), and rounded corners to match the chart tiles. */
  flex: 1 1 0;
  position: relative;
  display: flex;
  padding: 0 1.5rem 1.5rem;
}
#map { flex: 1 1 auto; width: 100%; border-radius: var(--radius); overflow: hidden; }
#rail-spacer { flex: 0 0 0px; }

/* Analyse: the map fills the whole rail; the list collapses (instant, no animation). */
#left-rail.map-full #building-list-panel {
  flex-grow: 0;
  flex-basis: 0;
  opacity: 0;
  pointer-events: none;
  overflow: hidden;
  /* Zero the padding too — a border-box flex item can't shrink below its
     padding, so it would otherwise keep ~1.35rem of height and offset the map. */
  padding: 0;
}
#left-rail.map-full #minimap-panel {
  flex: 1 1 auto;
  /* Map fills the whole rail here — add the top gap (the building list, which
     normally supplies it, is collapsed) so it matches the content's padding. */
  padding-top: 1.5rem;
}
#left-rail.map-full #rail-spacer { flex-basis: 0 !important; }

/* Sandbox: the config list replaces the ranking list in the top slot; the map
   stays below (1:1 split, same as the overview rail). The panel swap is instant
   (no transition) so the search box appears to stay put across view switches;
   only the map (#minimap-panel) animates its height. */
#sandbox-rail-panel {
  flex: 0 0 0;
  min-height: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
  display: flex;
  flex-direction: column;
  /* No padding while inactive — a border-box flex item can't shrink below its
     padding, so it would otherwise occupy ~1.35rem in Übersicht/Analyse and
     offset the map. Padding is applied only on the active sandbox panel below. */
  padding: 0;
}
#left-rail.sandbox-rail #building-list-panel {
  flex-grow: 0;
  flex-basis: 0;
  opacity: 0;
  pointer-events: none;
  overflow: hidden;
  /* Collapse padding so the panel takes zero height and the sandbox search box
     sits at the very top of the rail, exactly like the Übersicht search. */
  padding: 0;
}
#left-rail.sandbox-rail #sandbox-rail-panel {
  flex: 1 1 0;
  opacity: 1;
  pointer-events: auto;
  /* Same inset as the Übersicht list panel so the search box lines up. */
  padding: 0.85rem 1.5rem 0.5rem;
}
#left-rail.sandbox-rail .sandbox-building-list {
  flex: 1 1 auto;
  min-height: 0;
  max-height: none;
}
#left-rail.sandbox-rail #sandbox-bl-pager,
#left-rail.sandbox-rail .sandbox-fleet-battery { flex: 0 0 auto; }
/* The pager now sits between list and battery, so the battery is its own card. */
#left-rail.sandbox-rail .sandbox-fleet-battery {
  border-top: 1px solid var(--color-border);
  border-radius: var(--radius);
  margin-top: 0.5rem;
}

/* === Sidebar (content area) === */
#sidebar {
  background: var(--color-surface);
  overflow-y: auto;
  overflow-x: hidden;
  /* Always reserve the scrollbar gutter so switching between a view that fits
     (Übersicht) and one that overflows (Analyse) never shifts the content width
     — no horizontal jump when the scrollbar toggles. */
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: var(--color-border) transparent;
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
}
#sidebar-content { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
/* Bottom breathing room for scrolling views: #sidebar-content shrinks to the
   visible height (flex item) while its children overflow below it, so its own
   padding-bottom would land mid-content. A non-shrinking spacer placed after
   the content flows past the last section instead, guaranteeing a gap at the
   scroll end. Übersicht (fill-viewport) simply doesn't include one. */
/* The spacer is the single gap below scrolling content, sized to match the map's
   bottom margin (1.5rem) so the last content row lines up with the map bottom
   when scrolled to the end. Collapse the trailing margins of the block right
   before it (and that block's last descendants) so they don't add to the gap. */
.sidebar-bottom-spacer { flex: 0 0 1.5rem; }
#sidebar-content > *:has(+ .sidebar-bottom-spacer) { margin-bottom: 0; }
#sidebar-content > *:has(+ .sidebar-bottom-spacer) :last-child { margin-bottom: 0; }
/* Übersicht / detail: the paged chart units fill the viewport height so the
   page needs no scrollbar in the wide layout. The chart-container min-height
   (150px) restores normal scrolling on short screens or once the charts stack
   one-column ("second-stage collapse") / on mobile. */
#overview-profile-sections, #compare-fill { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
/* The energy-balance panel and the Bezug/PV stat grid keep their natural height
   (never shrink) so only the charts below absorb the flex stretch — otherwise the
   flex column squeezes the panel and crams the Bezug/PV cards. A little vertical
   breathing room separates the three blocks. */
#overview-profile-sections > .overview-balance { flex: 0 0 auto; }
#overview-profile-sections > .viz-grid { flex: 0 0 auto; margin: 1.25rem 0; }
/* The units split the height evenly (flex 1 1 0 + min-height:0 → a clean, sync
   distribution so the Bezug and PV charts in a unit always get the SAME height
   and their x-axes line up). On tall screens they fill the viewport; the
   min-height below keeps them readable and makes a short screen scroll (the
   #sidebar overflow) instead of squishing the charts. */
.chart-units { flex: 1 1 auto; min-height: 28rem; display: flex; flex-direction: column; gap: 1.25rem; }
.chart-units .chart-unit { flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; margin-bottom: 0; }
.chart-units .chart-pager { flex: 0 0 auto; }
.chart-units .chart-unit-row { flex: 1 1 0; min-height: 0; }
/* In the full-height layout the Bezug | PV pair must stay side by side: if it
   collapsed to one column (auto-fit at narrow widths) the two stacked charts
   would overflow their flex-sized row and overlap the unit below. */
.chart-units .chart-unit-row:not(.chart-unit-row--full) { grid-template-columns: 1fr 1fr; }
.chart-units .chart-container { min-height: 150px; height: 100%; margin-bottom: 0; }
#sidebar::-webkit-scrollbar { width: 6px; }
#sidebar::-webkit-scrollbar-track { background: transparent; }
#sidebar::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 3px; }

.loading {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
  color: var(--color-text-muted);
}

/* === Building Detail === */
.building-header { margin-bottom: 1.25rem; }
.building-header h2 { font-size: 1.1rem; font-weight: 600; margin-bottom: 0.25rem; line-height: 1.5rem; }
.building-header .address { color: var(--color-text-muted); font-size: 0.8rem; }
/* Status-pill instances that need extra trim (base recipe lives by .heat-carrier). */
.ara-live-badge { --pill: var(--color-accent); margin-left: 0.5rem; animation: ara-live-pulse 2s ease-in-out infinite; }
.ara-live-badge--stale { --pill: #f59e0b; animation: none; }
@keyframes ara-live-pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.45; } }

/* === Stat Cards === */
.stat-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem;
  margin-bottom: 1.25rem;
}
.stat-card {
  background: var(--color-bg);
  border-radius: var(--radius);
  padding: 0.7rem 0.75rem;
  border: 1px solid var(--color-border);
  display: flex;
  flex-direction: column;
}
/* Positive-milestone highlight — e.g. the sandbox "Überschuss" tile once a
   real PV surplus is reached. Greenish tint so it visibly reacts. */
.stat-card--positive {
  border-color: color-mix(in srgb, var(--color-accent) 50%, var(--color-border));
  background: color-mix(in srgb, var(--color-accent) 9%, transparent);
}
.stat-card--positive .value { color: var(--color-accent); }
/* One-shot green glow when the tile flips positive (e.g. surplus first reached). */
.stat-card--pulse { animation: stat-card-pulse 1s ease-out 1; }
@keyframes stat-card-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-accent) 55%, transparent); }
  35%  { box-shadow: 0 0 16px 4px color-mix(in srgb, var(--color-accent) 50%, transparent); }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.stat-card .label { font-size: 0.6rem; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.06em; line-height: 1.3; }
/* Keep the ⓘ icon from inflating the label line height so cards with an info
   tooltip (PV/ARA) stay the same height as cards without one (Seewasserwerk). */
.stat-card .label .info-trigger { font-size: inherit; line-height: 1; }
.stat-card .value { font-size: 1.05rem; font-weight: 600; margin-top: auto; padding-top: 0.15rem; }
.stat-card .unit { font-size: 0.6rem; font-weight: 400; color: var(--color-text-muted); }
/* ARA live row: the "Aktuelle Last" tile carries a Strasse-breakdown sub-line, so
   it's taller and the grid stretches both tiles. Top-align the value here (instead
   of the default bottom margin-top:auto) so the number sits under its label and
   lines up with the neighbouring tile, like every other Kennzahl. */
#ara-live-cards .stat-card .value { margin-top: 0; }

/* === Info Popup (reusable) === */
.info-wrap {
  position: relative;
  display: inline-block;
  text-transform: none;
  letter-spacing: normal;
}
.info-trigger {
  cursor: help;
  font-size: 0.7rem;
  color: var(--color-text-muted);
  opacity: 0.6;
  vertical-align: baseline;
}
.info-trigger:hover { opacity: 1; }
.info-panel {
  display: none;
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  top: 1.4rem;
  z-index: 20;
  width: 240px;
  font-size: 0.62rem;
  font-weight: 400;
  line-height: 1.5;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0.5rem 0.65rem;
  box-shadow: 0 4px 12px rgba(0,0,0,0.4);
}
.info-wrap:hover .info-panel,
.info-trigger:focus + .info-panel {
  display: block;
}

/* === Section Headings === */
.section-heading {
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  margin-bottom: 0.5rem;
  padding-bottom: 0.25rem;
  border-bottom: 2px solid var(--color-bezug);
}
.section-heading.pv-heading {
  border-bottom-color: var(--color-einspeisung);
  margin-top: 1.5rem;
}
.chart-title:empty { display: none; }
.section-heading .meter-count {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  opacity: 0.6;
  font-size: 0.75rem;
}

/* === Chart Tabs === */
.chart-tabs {
  display: flex;
  gap: 0.25rem;
  margin-bottom: 1rem;
  border-bottom: 1px solid var(--color-border);
  padding-bottom: 0;
}
.chart-tab {
  padding: 0.45rem 0.7rem;
  font-size: 0.75rem;
  cursor: pointer;
  border: none;
  background: none;
  color: var(--color-text-muted);
  border-bottom: 2px solid transparent;
  transition: all 0.15s;
  font-family: var(--font);
}
.chart-tab:hover { color: var(--color-text); }
.chart-tab.active { color: var(--color-primary); border-bottom-color: var(--color-primary); }

/* === Chart Container === */
.chart-container {
  position: relative;
  margin-bottom: 1.25rem;
  background: var(--color-bg);
  border-radius: var(--radius);
  padding: 1rem;
  border: 1px solid var(--color-border);
  min-height: calc(var(--chart-height) + 2rem);
}
.chart-container svg { width: 100%; height: var(--chart-height); }
.chart-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  min-height: var(--chart-height);
  color: var(--color-text-muted);
  font-size: 0.8rem;
}

/* === Side-by-side viz cards (tiles above each chart) === */
.viz-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
  gap: 1.25rem;
  align-items: stretch;
  margin-bottom: 0.5rem;
}
/* Cards stretch to equal height and push their chart to the bottom so the
   charts line up across the row even when one side has fewer tiles / no data. */
.viz-card { min-width: 0; display: flex; flex-direction: column; }
/* Span the whole grid row — used for the wide Solarausbau table that needs the
   full content width while sitting under a row of two narrower cards. */
.viz-card--full { grid-column: 1 / -1; }
/* Forced 50/50 pair (e.g. the two Spitzenlast tables): always side by side and
   each filling its half of the container, instead of wrapping like auto-fit. */
.viz-grid--pair { grid-template-columns: 1fr 1fr; }
.viz-card .chart-container { margin-top: auto; }
/* In a chart pair the cards stretch to equal height; let each chart box fill its
   card so an empty-state placeholder matches the height of the populated chart
   beside it (and both grow together when data appears). */
.viz-grid--pair .chart-container { flex: 1 1 auto; }
.sandbox-compare-scroll { overflow-x: auto; }
/* Stacked profile charts (one per active Tag/Woche/… pill). The Bezug and PV
   stat-card blocks are equal height (PV renders matching '–' tiles when empty),
   so top-aligning the stacks keeps the per-tab chart titles in line across the
   row — bottom-aligning would drift them when one chart is taller (e.g. a
   legend) or one side shows the no-data placeholder. */
.viz-card > .profile-stack { margin-top: 0; display: flex; flex-direction: column; }
.viz-card .profile-stack .chart-container { margin-top: 0; margin-bottom: 0; }
.viz-card .profile-stack .chart-title { margin-top: 1.1rem; }
.viz-card .profile-stack > .chart-title:first-child { margin-top: 0; }
/* PV-side chart titles take the einspeisung accent to match the PV heading. */
.profile-stack--pv .chart-title { border-bottom-color: var(--color-einspeisung); }
/* Paged chart units: one shared pager controlling a Bezug | PV chart row. */
.chart-unit { margin-bottom: 1.25rem; }
.chart-unit-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
  gap: 1.25rem;
}
.chart-unit-row--full { grid-template-columns: 1fr; }
.chart-unit-row .chart-container { margin-bottom: 0; }

/* === Vergleich: fixed slots, each a self-contained unit (Bezug + PV info
   boxes on top, one solo-paged chart below). Units stack and the page scrolls;
   no fill-the-viewport sizing here. A unit is a drop target for a building
   dragged from the rail list. === */
/* 2×2 grid of units, filling the viewport height (two equal rows) so the bottom
   row of graphs lines up with the rail map's bottom — no scrollbar on tall
   screens. min-height keeps it readable + scrolls on short screens. */
.compare-units {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 1.5rem;
  flex: 1 1 auto;
  min-height: 40rem;
}
/* Collapse to a single column when the content area gets too narrow to hold two
   units side by side; units then take a natural height and the page scrolls. */
@media (max-width: 1180px) {
  .compare-units { grid-template-columns: 1fr; grid-template-rows: none; grid-auto-rows: minmax(24rem, 1fr); }
}
/* Keep the Bezug | PV info boxes side by side inside the narrower 2×2 cell
   (override viz-grid's auto-fit, which would otherwise stack them). */
.compare-unit-info.viz-grid { grid-template-columns: 1fr 1fr; margin-bottom: 0; }
/* Each info box is a single row of two key tiles. */
.compare-stat-row { grid-template-columns: repeat(2, 1fr); gap: 0.4rem; margin-bottom: 0; }
.compare-unit {
  /* No border/padding: content sits flush like the Übersicht viz-cards, so the
     "Bezug"/"PV" headings line up exactly across the two views. Card separation
     comes from the grid gap; empty/drop states use outline (no layout shift). */
  border-radius: var(--radius);
  transition: outline-color 0.15s;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
.compare-unit--empty { outline: 1px dashed var(--color-border); outline-offset: 6px; }
.compare-unit.drop-hover { outline: 2px solid var(--color-primary); outline-offset: 6px; }
.compare-unit .compare-unit-info { margin-bottom: 0.5rem; flex: 0 0 auto; }
/* The graph fills the rest of the unit so the bottom row of charts lines up
   with the rail map bottom (info row + head + pager are fixed height). */
.compare-unit .compare-unit-graph { flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; margin-bottom: 0; }
.compare-unit .compare-unit-head,
.compare-unit .chart-pager { flex: 0 0 auto; }
.compare-unit .chart-unit-row { flex: 1 1 0; min-height: 0; }
.compare-unit .chart-container { height: 100%; min-height: 120px; margin-bottom: 0; }
/* HT/NT and load-heatmaps fill their box too. */
.compare-unit-graph .heatmap-wrapper { height: 100%; margin-bottom: 0; overflow: hidden; display: flex; flex-direction: column; justify-content: center; }
.compare-unit-graph .heatmap-title { display: none; }
.compare-unit-graph .heatmap-table:not(.coincidence-table) { height: 100%; max-height: 300px; }
.compare-unit-graph .heatmap-table td,
.compare-unit-graph .heatmap-table th { padding: 0 0.1rem; line-height: 1; }
.compare-unit-graph .heatmap-table:not(.coincidence-table) td,
.compare-unit-graph .heatmap-table:not(.coincidence-table) th,
.compare-unit-graph .heatmap-table:not(.coincidence-table) .hm-hour { font-size: 0.5rem; }
/* Fixed height so a slot doesn't nudge its chart down when it fills (the × button
   is taller than the bare "Leeres Feld" text). */
.compare-unit-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.35rem; min-height: 1.6rem; }
.compare-unit-name { font-size: 0.85rem; font-weight: 600; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.compare-unit-name--empty { color: var(--color-text-muted); font-weight: 400; font-style: italic; }
.compare-unit-remove {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
  border: 1px solid var(--color-border); background: var(--color-bg);
  color: var(--color-text-muted); cursor: pointer; font-size: 1rem; line-height: 1;
  display: flex; align-items: center; justify-content: center; padding: 0; transition: all 0.15s;
}
.compare-unit-remove:hover { border-color: #f87171; color: #f87171; }
/* Dragging a rail row shows it can be dropped. */
.ranking-list.bl-comparing .ranking-item[draggable="true"] { cursor: grab; }
/* A load-heatmap fills its chart box to the same height as the line/bar charts
   (no extra scroll). The pager already names it, so drop the inner grid title. */
.chart-units .heatmap-wrapper {
  height: 100%;
  margin-bottom: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: center;   /* compact load-heatmap centred in its box */
}
/* Load-heatmaps: the pager already names them, so drop the inner grid title.
   Koinzidenz (full-width) keeps its title since it explains the metric. */
.chart-unit-row:not(.chart-unit-row--full) .heatmap-wrapper .heatmap-title { display: none; }
.chart-units .heatmap-title { flex: 0 0 auto; margin-bottom: 0.3rem; }
/* Load-heatmaps fill their box so all 24 rows are always visible and the rows
   shrink to stay short; capped so they don't get tall when there's lots of space. */
.chart-units .heatmap-table:not(.coincidence-table) { height: 100%; max-height: 300px; }
.chart-units .heatmap-table td,
.chart-units .heatmap-table th { padding: 0 0.1rem; line-height: 1; }
.chart-units .heatmap-table:not(.coincidence-table) td,
.chart-units .heatmap-table:not(.coincidence-table) th,
.chart-units .heatmap-table:not(.coincidence-table) .hm-hour { font-size: 0.5rem; }
/* Koinzidenz: use full width, abbreviations on both axes, and scroll if the
   matrix is taller than its box rather than squishing it. */
.chart-units .chart-unit-row--full .heatmap-wrapper { overflow: auto; justify-content: flex-start; }
.chart-units .coincidence-table { width: 100%; }
.chart-units .coincidence-table td,
.chart-units .coincidence-table th { padding: 0.05rem 0.1rem; font-size: 0.55rem; }
/* Horizontal (0°) 4-letter column labels, kept visible while scrolling. */
.chart-units .coinc-col-header {
  writing-mode: horizontal-tb;
  transform: none;
  text-align: center !important;
  max-height: none;
}
.chart-units .coincidence-table thead th {
  position: sticky;
  top: 0;
  background: var(--color-surface);
  z-index: 1;
}
/* Chart-pager header: ‹ title › — a paged unit's mode selector (spans both columns). */
.chart-pager { display: flex; align-items: center; gap: 0.5rem; border-bottom: none; padding-bottom: 0; }
.chart-pager-title { flex: 1 1 auto; text-align: center; }
.chart-page-btn {
  flex: 0 0 auto;
  width: 22px; height: 22px; border-radius: 50%;
  border: 1px solid var(--color-border); background: var(--color-bg);
  color: var(--color-text); cursor: pointer; font-size: 0.85rem; line-height: 1;
  display: flex; align-items: center; justify-content: center;
  transition: all 0.15s; padding: 0;
}
.chart-page-btn:hover {
  color: var(--color-bezug);
  background: color-mix(in srgb, var(--color-bezug) 14%, transparent);
  border-color: color-mix(in srgb, var(--color-bezug) 55%, transparent);
}
/* Side-by-side cards share a top edge — drop the stacked-layout PV gap so the
   Bezug and PV headings/charts align. */
.viz-card .section-heading.pv-heading { margin-top: 0; }
.viz-card > h3 { font-size: 0.9rem; font-weight: 600; margin-bottom: 0.4rem; }
.viz-card .section-desc { font-size: 0.78rem; color: #7a7f8e; margin: -0.2rem 0 0.6rem; }
/* Inside a card the stat tiles and chart already carry their own spacing. */
.viz-card .stat-cards { margin-bottom: 0.6rem; }
.viz-card .chart-container { margin-bottom: 0; }

/* === D3 Chart Styles === */
.d3-tooltip {
  position: absolute;
  pointer-events: none;
  background: #1a1d24ee;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 0.68rem;
  color: var(--color-text-muted);
  z-index: 10;
  white-space: nowrap;
  line-height: 1.5;
}
.d3-tooltip .tt-label { color: var(--color-text); }
.d3-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  padding: 2px 0 6px;
  font-size: 0.68rem;
  color: var(--color-text-muted);
}
.d3-legend-item { display: flex; align-items: center; gap: 4px; cursor: default; }
.d3-legend-swatch { width: 14px; height: 3px; border-radius: 1px; flex-shrink: 0; }
.d3-crosshair { stroke: var(--color-text-muted); stroke-width: 0.5; stroke-dasharray: 3,3; }

/* === Chart Options (sub-toggles) === */
.chart-options {
  display: flex;
  gap: 0.4rem;
  margin-bottom: 0.75rem;
  flex-wrap: wrap;
}
.chart-option {
  padding: 0.2rem 0.55rem;
  font-size: 0.65rem;
  border-radius: 10px;
  cursor: pointer;
  border: 1px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-text-muted);
  font-family: var(--font);
  transition: all 0.15s;
}
.chart-option:hover { border-color: var(--color-text-muted); color: var(--color-text); }
/* Tinted active state — matches .fp-pill.active so all control pills agree. */
.chart-option.active {
  color: var(--color-bezug);
  background: color-mix(in srgb, var(--color-bezug) 16%, transparent);
  border-color: color-mix(in srgb, var(--color-bezug) 55%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-bezug) 30%, transparent);
}

/* === Narrative Section === */
.narrative-section { margin-top: 1.5rem; }
.narrative-section h3 { font-size: 0.85rem; font-weight: 600; margin-bottom: 0.5rem; }
.narrative-text {
  font-size: 0.8rem;
  line-height: 1.6;
  color: var(--color-text-muted);
  padding: 0.75rem;
  background: var(--color-bg);
  border-radius: var(--radius);
  border: 1px solid var(--color-border);
  min-height: 60px;
}

/* === Overview === */
.overview-section { margin-bottom: 1.5rem; }
/* A section that only holds stat tiles (PV-Bilanz, Anteile, HT/NT, …) sits
   directly above the chart grid — drop the tile block's trailing margin and
   tighten the section gap so the boxes sit close to the charts that follow. */
.overview-section .stat-cards:last-child { margin-bottom: 0; }
.overview-section:has(.stat-cards:last-child) { margin-bottom: 0.75rem; }
.overview-section h3 { font-size: 0.9rem; font-weight: 600; margin-bottom: 0.75rem; }
.overview-section .section-desc { font-size: 0.78rem; color: #7a7f8e; margin: -0.5rem 0 0.75rem; }
.overview-section h4 { font-size: 0.85rem; font-weight: 600; margin: 1rem 0 0.5rem; }

.ranking-sort { display: flex; gap: 0.4rem; margin-bottom: 0.6rem; }
.ranking-list { list-style: none; }
.ranking-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0.45rem 0;
  border-bottom: 1px solid var(--color-border);
  cursor: pointer;
  transition: all 0.1s;
}
.ranking-item:hover, .ranking-item.hover { background: var(--color-bg); margin: 0 -0.5rem; padding-left: 0.5rem; padding-right: 0.5rem; border-radius: var(--radius); }
.ranking-item.selected { background: rgba(99,179,237,0.1); margin: 0 -0.5rem; padding-left: 0.5rem; padding-right: 0.5rem; border-radius: var(--radius); border-left: 2px solid var(--color-primary); }
.ranking-item .rank { width: 1.5rem; font-size: 0.75rem; color: var(--color-text-muted); }
.ranking-item .name { flex: 1; font-size: 0.8rem; }
.ranking-item .kwh { font-size: 0.75rem; color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
.ranking-item .fleet-pct { color: var(--color-text-muted); opacity: 0.7; font-size: 0.7rem; }

/* Rail list rows: lay out as aligned columns so ranks, type dots, warnings,
   values and percentages each line up vertically across rows. */
.bl-list .ranking-item {
  display: grid;
  grid-template-columns: 1.4rem 0.9rem 12px minmax(0, 1fr) auto 3.1rem;
  align-items: center;
  gap: 0.45rem;
  justify-content: initial;
}
.bl-list .ranking-item .rank { width: auto; text-align: left; font-variant-numeric: tabular-nums; }
.bl-list .ranking-item .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bl-list .ranking-item .kwh { text-align: right; }
.bl-list .ranking-item .fleet-pct { text-align: right; }
/* Type dot — mirrors the map marker colours (Bezug blue, PV yellow, both split). */
.bl-type {
  width: 10px; height: 10px; border-radius: 50%;
  justify-self: center; opacity: 0.9;
}
.bl-type--bezug { background: #4f8cff; }
.bl-type--pv { background: #facc15; }
.bl-type--both { background: linear-gradient(90deg, #4f8cff 0 50%, #facc15 50% 100%); }
.bl-type--nodata { background: #64748b; }
.bl-nodata { color: var(--color-text-muted); }
.bl-warn { display: flex; justify-content: center; }
.bl-warn .warning-icon { margin: 0; }

/* === Comparison === */
.compare-info {
  font-size: 0.8rem;
  color: var(--color-text-muted);
  margin-bottom: 1rem;
  padding: 0.75rem;
  background: var(--color-primary-light);
  border-radius: var(--radius);
  border: 1px solid var(--color-border);
}
.compare-chips { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; }
.compare-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  /* Pill-shaped to match the unified badge language; tighter on the ✕ side. */
  padding: 0.22rem 0.4rem 0.22rem 0.6rem;
  background: color-mix(in srgb, var(--color-text-muted) 10%, transparent);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  font-size: 0.72rem;
}
.compare-chip .remove {
  cursor: pointer;
  color: var(--color-text-muted);
  font-weight: bold;
}
.compare-chip .remove:hover { color: #f87171; }
.compare-chip.no-data, .compare-chip.no-data-year {
  opacity: 0.5;
  border-style: dashed;
}
.compare-chip .chip-hint {
  font-size: 0.65rem;
  color: var(--color-text-muted);
  font-style: italic;
}

/* === Data Warnings === */
.data-warning {
  font-size: 0.75rem;
  color: #f59e0b;
  background: rgba(245, 158, 11, 0.08);
  border: 1px solid rgba(245, 158, 11, 0.2);
  border-radius: var(--radius);
  padding: 0.5rem 0.75rem;
  margin-bottom: 0.75rem;
}
.data-warning--critical {
  color: #f87171;
  background: rgba(248, 113, 113, 0.08);
  border-color: rgba(248, 113, 113, 0.2);
}
.data-warning--info {
  color: var(--color-primary);
  background: rgba(79, 140, 255, 0.08);
  border-color: rgba(79, 140, 255, 0.15);
}
.data-warning--success {
  color: #34d399;
  background: rgba(52, 211, 153, 0.08);
  border-color: rgba(52, 211, 153, 0.2);
}
.warning-icon {
  color: #f59e0b;
  font-size: 0.75rem;
  cursor: help;
}
.warning-icon--critical { color: #ef4444; }

/* === Data Quality Section === */
.dq-section {
  margin-bottom: 1rem;
}
.dq-header {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
  user-select: none;
  margin-bottom: 0.4rem;
}
.dq-label {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.dq-count {
  font-size: 0.6rem;
  color: #f59e0b;
  margin-left: auto;
}
.dq-chevron { font-size: 0.55rem; color: var(--color-text-muted); }
.dq-bar-track {
  height: 3px;
  background: rgba(255,255,255,0.06);
  border-radius: 2px;
  overflow: hidden;
}
.dq-bar-fill {
  height: 100%;
  background: var(--color-accent);
  border-radius: 2px;
  transition: width 0.4s ease;
}
.dq-list {
  margin-top: 0.5rem;
}
.dq-item {
  display: flex;
  align-items: flex-start;
  gap: 0.4rem;
  padding: 0.3rem 0;
  cursor: pointer;
  transition: opacity 0.12s;
}
.dq-item:hover { opacity: 0.75; }
.dq-dot {
  flex-shrink: 0;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  margin-top: 0.32rem;
}
.dq-dot--critical { background: #f87171; }
.dq-dot--warning { background: #f59e0b; }
.dq-dot--info { background: #60a5fa; }
.dq-building {
  font-size: 0.65rem;
  font-weight: 600;
  white-space: nowrap;
  flex-shrink: 0;
}
.dq-text {
  font-size: 0.6rem;
  color: var(--color-text-muted);
  line-height: 1.3;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  min-width: 0;
}
/* In the floating popups show the full text (no ellipsis) — there's room. */
.dq-popup .dq-text { white-space: normal; overflow: visible; text-overflow: clip; font-size: 0.74rem; }
/* When an item carries a building name, stack the description on its own line so
   a long description wraps across the full popup width instead of being squeezed
   into a narrow column beside the (nowrap) building name. */
.dq-popup .dq-item:has(.dq-building) { flex-wrap: wrap; }
.dq-popup .dq-item:has(.dq-building) .dq-text { flex: 1 1 100%; margin-left: 0.65rem; }
.dq-popup .dq-building { font-size: 0.74rem; }

/* === No Data === */
.no-data-value { color: var(--color-text-muted) !important; }
.no-data-msg {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 120px;
  color: var(--color-text-muted);
  font-size: 0.8rem;
  font-style: italic;
}

/* === Map Tooltip === */
.map-tooltip {
  background: var(--color-surface) !important;
  border: 1px solid var(--color-border) !important;
  border-radius: 8px !important;
  color: var(--color-text) !important;
  padding: 0 !important;
  box-shadow: var(--shadow-lg) !important;
  font-family: var(--font) !important;
}
.map-tooltip .leaflet-tooltip-content { padding: 8px 10px; }
.map-tooltip--mini .leaflet-tooltip-content { padding: 4px 8px; font-size: 0.72rem; font-weight: 600; white-space: nowrap; }
.mtt-name { font-size: 0.75rem; font-weight: 600; margin-bottom: 4px; white-space: nowrap; }
.mtt-section { font-size: 0.6rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-bezug); margin-top: 4px; margin-bottom: 2px; }
.mtt-section.pv { color: var(--color-einspeisung); }
.mtt-nodata { font-size: 0.65rem; color: var(--color-text-muted); font-style: italic; }
.mtt-alert {
  font-size: 0.6rem;
  border-radius: 4px;
  padding: 3px 6px;
  margin-top: 3px;
}
.mtt-alert--critical { color: #f87171; background: rgba(248, 113, 113, 0.08); border: 1px solid rgba(248, 113, 113, 0.2); }
.mtt-alert--warning { color: #f59e0b; background: rgba(245, 158, 11, 0.08); border: 1px solid rgba(245, 158, 11, 0.2); }
.mtt-alert--info { color: var(--color-primary); background: rgba(79, 140, 255, 0.08); border: 1px solid rgba(79, 140, 255, 0.15); }
.map-tooltip::before { border-top-color: var(--color-surface) !important; }

/* Compact stat cards for map tooltip */
.stat-cards-compact { grid-template-columns: 1fr 1fr; gap: 3px; margin-bottom: 2px; }
.stat-card.compact {
  padding: 3px 6px;
  border-radius: 4px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
}
.stat-card.compact .label { font-size: 0.5rem; }
.stat-card.compact .value { font-size: 0.7rem; margin-top: 0; }
.stat-card.compact .unit { font-size: 0.5rem; }

/* === Map Markers === */
.map-marker { background: none !important; border: none !important; transition: margin-left 0.25s cubic-bezier(0.4, 0, 0.2, 1); }
/* Color-matched, layered glow so each dot reads as a lit point rather than a flat
   circle. A tight inner halo + a softer outer one in the marker's own colour.
   Default = Bezug blue; PV yellow, mixed warm, no-data red, sandbox-off none. */
.map-marker-svg { filter: drop-shadow(0 0 2.5px rgba(79, 140, 255, 0.6)) drop-shadow(0 0 6px rgba(79, 140, 255, 0.3)); }
.map-marker--pv .map-marker-svg,
.map-marker--sandbox-pv .map-marker-svg { filter: drop-shadow(0 0 2.5px rgba(250, 204, 21, 0.6)) drop-shadow(0 0 6px rgba(250, 204, 21, 0.3)); }
.map-marker--both .map-marker-svg,
.map-marker--sandbox-pvbat .map-marker-svg { filter: drop-shadow(0 0 2.5px rgba(250, 204, 21, 0.5)) drop-shadow(0 0 6px rgba(79, 140, 255, 0.3)); }
.map-marker--noData .map-marker-svg { filter: drop-shadow(0 0 2.5px rgba(100, 116, 139, 0.55)) drop-shadow(0 0 6px rgba(100, 116, 139, 0.3)); }
.map-marker--sandbox-off .map-marker-svg { filter: none; }
/* Selected: a brighter white-cored halo lifts the active building above the rest. */
.map-marker--selected .map-marker-svg { filter: drop-shadow(0 0 3px rgba(255, 255, 255, 0.55)) drop-shadow(0 0 8px rgba(79, 140, 255, 0.4)); }

/* Leaflet dark overrides */
.leaflet-control-attribution { background: rgba(15, 17, 23, 0.7) !important; color: #555 !important; font-size: 0.6rem !important; }
.leaflet-control-attribution a { color: #666 !important; }
.leaflet-control-zoom a { background: var(--color-surface) !important; color: var(--color-text) !important; border-color: var(--color-border) !important; }

/* === Scaling Table === */
.scaling-table + .data-warning { margin-top: 0.6rem; }
.scaling-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.75rem;
  background: var(--color-bg);
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--color-border);
}
.scaling-table th, .scaling-table td {
  padding: 0.45rem 0.6rem;
  text-align: right;
}
.scaling-table th {
  background: var(--color-border);
  font-weight: 600;
  font-size: 0.65rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}
.scaling-table td:first-child, .scaling-table th:first-child { text-align: left; }
.scaling-table tbody tr:not(:last-child) { border-bottom: 1px solid var(--color-border); }
.scaling-table tbody tr:hover { background: var(--color-surface); }

/* === Heatmap Table === */
.heatmap-wrapper { overflow-x: auto; margin-bottom: 1rem; }
.heatmap-title { font-size: 0.75rem; font-weight: 600; color: var(--color-text-muted); margin-bottom: 0.5rem; text-align: center; }
.heatmap-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.6rem;
  font-variant-numeric: tabular-nums;
  table-layout: fixed;
}
.heatmap-table th, .heatmap-table td {
  padding: 0.2rem 0.15rem;
  text-align: center;
  border: 1px solid var(--color-bg);
}
.heatmap-table th {
  font-weight: 600;
  font-size: 0.55rem;
  color: var(--color-text-muted);
  background: var(--color-bg);
}
.heatmap-table .hm-hour {
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-bg);
  text-align: right;
  padding-right: 0.3rem;
  white-space: nowrap;
  width: 3rem;
}

/* === Coincidence Matrix === */
.coincidence-table { table-layout: auto; }
.coincidence-table th, .coincidence-table td { font-size: 0.6rem; padding: 0.25rem 0.2rem; }
.coinc-row-header {
  text-align: right !important;
  padding-right: 0.4rem !important;
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-bg);
  white-space: nowrap;
  max-width: 8rem;
  overflow: hidden;
  text-overflow: ellipsis;
}
.coinc-col-header {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  text-align: left !important;
  font-weight: 600;
  white-space: nowrap;
  max-height: 6rem;
  overflow: hidden;
}

/* Analyse > Flotte: full-width Peak-Koinzidenz with larger, readable cells
   (the Übersicht pager squeezes this matrix into a fixed-height box). */
.flotte-coincidence .heatmap-wrapper { margin-bottom: 0; }
.flotte-coincidence .heatmap-title { display: none; }
.flotte-coincidence .coincidence-table td,
.flotte-coincidence .coincidence-table th { font-size: 0.7rem; padding: 0.45rem 0.4rem; }
/* Horizontal (0°) 4-letter column labels — the full-width matrix has the room. */
.flotte-coincidence .coinc-col-header {
  writing-mode: horizontal-tb;
  transform: none;
  text-align: center !important;
  max-height: none;
}
/* A description that follows a stat-card block keeps its normal top spacing
   (the default negative margin is meant to tuck it under a heading). */
.overview-section .stat-cards + .section-desc { margin-top: 0.5rem; }


/* === Sandbox === */
.sandbox-building-list {
  max-height: 260px;
  overflow-y: auto;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  scrollbar-width: thin;
  scrollbar-color: var(--color-border) transparent;
}
.sandbox-building-list::-webkit-scrollbar { width: 6px; }
.sandbox-building-list::-webkit-scrollbar-track { background: transparent; }
.sandbox-building-list::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 3px; }
.sandbox-building-item {
  padding: 0.35rem 0.5rem;
  border-bottom: 1px solid var(--color-border);
  transition: background 0.1s;
  cursor: pointer; /* whole row toggles PV */
}
.sandbox-building-item:last-child { border-bottom: none; }
/* Hover affordance for the clickable row — skip locked rows (not toggleable). */
.sandbox-building-item:not(.sandbox-building-item--locked):not(.sandbox-building-item--active):hover {
  background: color-mix(in srgb, var(--color-text) 4%, transparent);
}
.sandbox-building-item--locked { cursor: default; }
.sandbox-building-item--active {
  /* Scannable in a long list: a real tint + a left accent (inset box-shadow so
     it adds no 2px content shift), matching the unified tinted-pill language. */
  background: color-mix(in srgb, var(--color-bezug) 8%, transparent);
  box-shadow: inset 2px 0 0 var(--color-bezug);
}
.sandbox-building-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
}
.sandbox-toggle {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
  min-width: 0;
  user-select: none;
}
.sandbox-toggle input { display: none; }
.sandbox-toggle-track {
  position: relative;
  width: 40px;
  height: 22px;
  /* Off state reads as a hollow outline, not a solid grey pill, so a list of
     mostly-off toggles stops competing with the building names for attention. */
  background: var(--color-bg);
  box-shadow: inset 0 0 0 1px var(--color-border);
  border-radius: 11px;
  transition: background 0.2s, box-shadow 0.2s;
  flex-shrink: 0;
}
.sandbox-toggle-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  background: var(--color-text-muted);
  opacity: 0.65;
  border-radius: 50%;
  transition: transform 0.2s, background 0.2s, opacity 0.2s;
}
.sandbox-toggle input:checked + .sandbox-toggle-track {
  background: var(--color-primary);
  box-shadow: none;
}
.sandbox-toggle input:checked + .sandbox-toggle-track .sandbox-toggle-thumb {
  transform: translateX(18px);
  background: #fff;
  opacity: 1;
}
.sandbox-toggle--locked {
  cursor: default;
}
.sandbox-toggle--locked .sandbox-toggle-track {
  opacity: 0.6;
}
.sandbox-building-item--locked {
  /* Inset shadow (not border-left) so locked rows don't shift 2px vs the rest. */
  box-shadow: inset 2px 0 0 var(--color-primary);
}
.sandbox-building-name {
  font-size: 0.68rem;
  font-weight: 500;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sandbox-building-meta {
  font-size: 0.6rem;
  color: var(--color-text-muted);
  white-space: nowrap;
  flex-shrink: 0;
}
.sandbox-badge--good { --pill: var(--color-accent); }
.sandbox-badge--mid { --pill: var(--color-einspeisung); }
.sandbox-info-wrap {
  position: relative;
  display: inline-block;
}
.sandbox-info-trigger {
  cursor: help;
  font-size: 0.75rem;
  color: var(--color-text-muted);
  vertical-align: baseline;
}
.sandbox-info-panel {
  display: none;
  position: absolute;
  left: 0;
  top: 1.6rem;
  z-index: 10;
  width: 280px;
  font-size: 0.65rem;
  font-weight: 400;
  line-height: 1.5;
  color: var(--color-text-muted);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0.6rem 0.8rem;
  box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
.sandbox-info-panel a {
  color: var(--color-primary);
  text-decoration: none;
}
.sandbox-info-panel a:hover { text-decoration: underline; }
.sandbox-info-wrap:hover .sandbox-info-panel,
.sandbox-info-trigger:focus + .sandbox-info-panel {
  display: block;
}
.sandbox-card-sub {
  font-size: 0.55rem;
  color: var(--color-text-muted);
  margin-top: 0.2rem;
}
.sandbox-fleet-battery {
  padding: 0.6rem;
  border: 1px solid var(--color-border);
  border-top: none;
  border-radius: 0 0 var(--radius) var(--radius);
  background: var(--color-surface);
}
.sandbox-bfe-info {
  font-size: 0.6rem;
  color: var(--color-text-muted);
  margin-top: 0.2rem;
  padding-left: 2.2rem;
  font-style: italic;
}
.sandbox-sliders {
  margin-top: 0.35rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  transition: max-height 0.15s ease, opacity 0.15s ease;
  max-height: 100px;
  opacity: 1;
  overflow: hidden;
}
.sandbox-sliders--hidden {
  max-height: 0;
  opacity: 0;
  margin-top: 0;
}
.sandbox-slider-row {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}
.sandbox-slider-label {
  font-size: 0.6rem;
  color: var(--color-text-muted);
  width: 2rem;
  flex-shrink: 0;
}
.sandbox-slider {
  flex: 1;
  height: 4px;
  -webkit-appearance: none;
  appearance: none;
  background: var(--color-border);
  border-radius: 2px;
  outline: none;
  cursor: pointer;
  margin: 5px 0;
}
.sandbox-slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  cursor: pointer;
}
.sandbox-slider--pv::-webkit-slider-thumb { background: #facc15; }
.sandbox-slider--bat::-webkit-slider-thumb { background: #fb923c; }
.sandbox-slider::-moz-range-thumb {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: none;
  cursor: pointer;
}
.sandbox-slider--pv::-moz-range-thumb { background: #facc15; }
.sandbox-slider--bat::-moz-range-thumb { background: #fb923c; }
.sandbox-slider-value {
  font-size: 0.6rem;
  color: var(--color-text-muted);
  min-width: 7rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* Sandbox reuses .stat-cards / .stat-card grid from main styles */
.sandbox-comparison-highlight {
  background: #4f8cff18;
  font-weight: 600;
}
.sandbox-summary {
  margin-top: 0.5rem;
}

/* === Mobile filter toggle button === */
#btn-filter-mobile {
  display: none;
  align-items: center;
  gap: 0.3rem;
  padding: 0.25rem 0.6rem;
  font-size: 0.7rem;
  border-radius: var(--radius);
  cursor: pointer;
  border: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text-muted);
  font-family: var(--font);
}
#btn-filter-mobile.active {
  color: var(--color-primary);
  border-color: var(--color-primary);
}

/* === Responsive === */

/* Laptop / smaller desktop screens */
@media (max-width: 1440px) {
  #main { grid-template-columns: 560px 1fr; }
  #sidebar { padding: 1.1rem; }
  .stat-card .value { font-size: 0.95rem; }
  .stat-card { padding: 0.55rem 0.6rem; }
  .overview-section h3 { font-size: 0.82rem; }
  .building-header h2 { font-size: 0.95rem; }
}

@media (max-width: 1200px) {
  #main { grid-template-columns: 460px 1fr; }
  #sidebar { padding: 0.9rem; }
  .stat-card .value { font-size: 0.88rem; }
  .stat-card .label { font-size: 0.55rem; }
  .stat-card .unit { font-size: 0.55rem; }
  .stat-card { padding: 0.45rem 0.5rem; }
  .stat-cards { gap: 0.4rem; margin-bottom: 1rem; }
  .building-header h2 { font-size: 0.9rem; }
  .building-header .address { font-size: 0.7rem; }
  .overview-section h3 { font-size: 0.78rem; }
  .overview-section h4 { font-size: 0.75rem; }
  .ranking-item .name { font-size: 0.7rem; }
  .ranking-item .kwh { font-size: 0.65rem; }
  .narrative-section h3 { font-size: 0.75rem; }
  .narrative-body { font-size: 0.7rem; }
  :root { --chart-height: 270px; }
}

@media (max-width: 1024px) {
  #main { grid-template-columns: 360px 1fr; }
  #sidebar { padding: 0.75rem; }
  .stat-card .value { font-size: 0.8rem; }
  .stat-card .label { font-size: 0.5rem; }
  .stat-card .unit { font-size: 0.5rem; }
  .stat-card { padding: 0.4rem 0.45rem; }
  .stat-cards { gap: 0.3rem; }
  .building-header h2 { font-size: 0.85rem; line-height: 1.2rem; }
  .overview-section h3 { font-size: 0.75rem; }
  :root { --chart-height: 240px; }
}

@media (max-width: 768px) {
  /* Header: stack vertically */
  #header {
    flex-wrap: wrap;
    height: auto;
    padding: 0.5rem 1rem;
    gap: 0.3rem;
  }
  .header-left {
    width: 100%;
    gap: 0.4rem;
  }
  .brand-wordmark { height: 24px; }
  .brand-div { height: 18px; }
  .brand-mae-text { height: 15px; }
  .brand-mae-mark { height: 21px; }
  .header-left h1 { font-size: 0.8rem; }
  .header-right { gap: 0.4rem; }
  .header-right .btn { font-size: 0.7rem; padding: 0.25rem 0.6rem; }

  /* Filter panel: collapsible */
  #filter-panel {
    max-height: 0;
    overflow: hidden;
    transition: max-height 0.25s ease;
  }
  #filter-panel.open {
    max-height: 300px;
  }
  .filter-panel-inner {
    flex-direction: column;
    gap: 0.5rem;
    padding: 0.5rem 1rem;
  }

  /* Show filter toggle on mobile */
  #btn-filter-mobile {
    display: flex;
  }

  /* Main: building list on top (capped), minimap hidden, content below */
  #main { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  #left-rail {
    border-right: none;
    border-bottom: 1px solid var(--color-border);
  }
  /* Single-column: list sizes to content (capped); the 2:1 rail split and the
     minimap don't apply here. */
  #building-list-panel { max-height: 32vh; flex: 1 1 auto; }
  #minimap-panel { display: none; }
  #sidebar { padding: 1rem; }

  /* Smaller stat cards */
  .stat-card .value { font-size: 1rem; }
  .stat-card .label { font-size: 0.6rem; }
}

/* ===== Heating / energy bar lists (Analyse → Wärme, Gesamtenergie) ===== */
.heat-legend {
  display: flex; flex-wrap: wrap; gap: 0.4rem 1.1rem;
  font-size: 0.72rem; color: var(--color-text-muted); margin: 0 0 0.7rem;
}
.heat-legend i { display: inline-block; width: 0.7rem; height: 0.7rem; border-radius: 3px; margin-right: 0.35rem; vertical-align: -1px; }
.heat-dot--fossil { background: #fb923c; }
.heat-dot--lowco2 { background: var(--color-accent); }
.heat-dot--unknown { background: #5b6172; }

.heat-list { display: flex; flex-direction: column; gap: 0.4rem; }
.heat-row {
  position: relative; display: block; width: 100%; text-align: left;
  border: none; background: var(--color-bg); color: var(--color-text);
  border-radius: var(--radius); overflow: hidden; padding: 0;
  font: inherit;
}
.heat-fill {
  position: absolute; inset: 0 auto 0 0; height: 100%;
  border-radius: var(--radius); opacity: 0.85;
  transition: width 0.3s ease;
}
.heat-row--fossil .heat-fill { background: linear-gradient(90deg, rgba(251,146,60,0.10), rgba(251,146,60,0.32)); }
.heat-row--lowco2 .heat-fill { background: linear-gradient(90deg, rgba(52,211,153,0.10), rgba(52,211,153,0.30)); }
.heat-row--unknown .heat-fill { background: linear-gradient(90deg, rgba(91,97,114,0.12), rgba(91,97,114,0.30)); }
.heat-row--elec .heat-fill { background: linear-gradient(90deg, rgba(79,140,255,0.10), rgba(79,140,255,0.32)); }
.heat-row--suspect .heat-fill {
  background: repeating-linear-gradient(45deg, rgba(120,120,130,0.10), rgba(120,120,130,0.10) 6px, rgba(120,120,130,0.22) 6px, rgba(120,120,130,0.22) 12px);
}
.heat-content {
  position: relative; display: flex; align-items: center; gap: 0.6rem;
  padding: 0.5rem 0.8rem;
}
.heat-rank {
  flex: 0 0 1.4rem; text-align: right; font-size: 0.75rem;
  color: var(--color-text-muted); font-variant-numeric: tabular-nums;
}
.heat-name {
  flex: 1 1 auto; min-width: 0; font-size: 0.84rem; font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  display: flex; align-items: center; gap: 0.5rem;
}
.heat-val {
  flex: 0 0 auto; font-size: 0.84rem; font-weight: 600;
  font-variant-numeric: tabular-nums; color: var(--color-text);
}
.heat-row--link { cursor: pointer; transition: outline-color 0.15s; outline: 1px solid transparent; }
.heat-row--link:hover { outline-color: var(--color-primary); }

/* === Status pills (unified) ==========================================
   One recipe for every inline status/category pill: carrier (heat tile),
   sandbox rating, priority flag, ARA live. Translucent tint + matching text +
   1px inset ring, driven by a single --pill hue so each variant sets only a
   colour. Paint-only; markup/classes unchanged. (The Vergleich token —
   .compare-chip — is a separate editable component and stays as-is.) */
.heat-carrier, .sandbox-badge, .ara-live-badge {
  display: inline-block; vertical-align: middle; white-space: nowrap;
  padding: 0.12rem 0.5rem; border-radius: 999px; border: 0;
  font-size: 0.64rem; font-weight: 600; letter-spacing: 0.02em; line-height: 1.35;
  font-variant-numeric: tabular-nums;
  color: var(--pill, var(--color-text-muted));
  background: color-mix(in srgb, var(--pill, var(--color-text-muted)) 15%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pill, var(--color-text-muted)) 32%, transparent);
}
.heat-carrier { flex: 0 0 auto; }
.heat-carrier--fossil { --pill: #fb923c; }
.heat-carrier--lowco2 { --pill: var(--color-accent); }
.heat-carrier--unknown { --pill: #7a8095; }
.heat-flag { font-size: 0.7rem; font-weight: 600; color: #fbbf24; white-space: nowrap; }
.heat-noelec { font-size: 0.66rem; color: var(--color-text-muted); white-space: nowrap; }

/* Split bars: Wärme vs Strom for energy + CO2 */
.split-bar {
  display: flex; height: 2.4rem; border-radius: var(--radius);
  overflow: hidden; margin: 0.3rem 0 0.7rem;
  /* overflow:hidden clips segments to the rounded shape so both ends round
     cleanly even when the end carrier is a hair-thin sliver. The glow lives on
     the container (a box-shadow is NOT clipped by overflow:hidden) so the bar
     still reads glowy like the rest of the page. */
  box-shadow: 0 3px 16px rgba(0, 0, 0, 0.40), 0 0 14px rgba(143, 179, 224, 0.10);
}
.split-seg {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.8rem; font-weight: 700; color: #0f1117;
  min-width: 0; transition: width 0.3s ease;
}
/* Outer corners round on the first/last segment regardless of segment type. */
.split-bar > :first-child { border-radius: var(--radius) 0 0 var(--radius); }
.split-bar > :last-child { border-radius: 0 var(--radius) var(--radius) 0; }
/* Top-light gradient fill + a soft colour-matched glow underneath/around. */
.split-seg--heat {
  background: linear-gradient(180deg, #fdba74, #fb923c);
  box-shadow: 0 0 9px rgba(251, 146, 60, 0.22), 0 2px 7px rgba(251, 146, 60, 0.15);
}
.split-seg--elec {
  background: linear-gradient(180deg, #6ba0ff, var(--color-bezug));
  box-shadow: 0 0 9px rgba(79, 140, 255, 0.24), 0 2px 7px rgba(79, 140, 255, 0.16);
}
/* Per-carrier stacked segment (Energieverbrauch + CO₂ bars). Fill + glow are set
   inline per carrier; this just handles layout + the inline % label. */
.stack-seg {
  position: relative; overflow: hidden; white-space: nowrap;
  display: flex; align-items: center; justify-content: center;
  font-size: 0.72rem; font-weight: 700; color: #0f1117;
  min-width: 0; transition: width 0.3s ease;
}

/* Per-carrier detail list: carrier label + an Energie and a CO₂ mini-bar each,
   continuing the energy/emissions split from the two stacked bars above. */
.carrier-swatch { width: 11px; height: 11px; border-radius: 3px; flex: 0 0 auto; }
.carrier-split-list { display: flex; flex-direction: column; gap: 0.7rem; }
.csr { display: grid; grid-template-columns: 170px 1fr; gap: 0.3rem 1rem; align-items: center; }
.csr-head { display: flex; align-items: center; gap: 0.5rem; min-width: 0; }
.csr-name { font-size: 0.84rem; font-weight: 500; color: var(--color-text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.csr-bars { display: flex; flex-direction: column; gap: 0.28rem; min-width: 0; }
.csb { display: flex; align-items: center; gap: 0.55rem; }
.csb-tag { flex: 0 0 3.4rem; font-size: 0.66rem; letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-text-muted); }
.csb-track { position: relative; flex: 1 1 auto; height: 0.8rem; min-width: 0; background: var(--color-bg); border-radius: 5px; overflow: hidden; }
.csb-fill { position: absolute; left: 0; top: 0; height: 100%; border-radius: 5px;
  transition: width 0.5s cubic-bezier(0.22, 1, 0.36, 1); }
/* Blurred ghost of the Aktuell baseline behind the fill: the soft tail beyond
   the solid bar is the reduction a scenario removes. Stays faint (never boosts
   to full opacity); dims in last during a scenario switch (.ghost-pending = 0). */
.csb-ghost { position: absolute; left: 0; top: 0; height: 100%; border-radius: 5px;
  background: #64748b; opacity: 0.4; filter: blur(2.5px); transition: opacity 0.45s ease; }
.csb-ghost.ghost-pending { opacity: 0; }
/* Value cell holds the current figure + a signed reduction (%) — widened so both
   fit on one line, which also shortens the bar track (room for the numbers). */
.csb-val { flex: 0 0 auto; width: 9.5rem; text-align: right; font-size: 0.76rem;
  font-variant-numeric: tabular-nums; color: var(--color-text);
  display: inline-flex; gap: 0.4rem; justify-content: flex-end; align-items: baseline; }
.csb-cur { white-space: nowrap; }
.csb-cur--add { color: var(--color-accent); font-weight: 600; } /* new solar = good */
.csb-delta { font-size: 0.68rem; font-weight: 600; white-space: nowrap; }
.csb-delta.is-down { color: var(--color-accent); }
.csb-delta.is-up { color: #fb923c; }
/* Reduction chip on the energy-balance headline tiles (green when down). */
.stat-delta { margin-left: 0.4rem; font-size: 0.62em; font-weight: 700; vertical-align: middle; }
.stat-delta .is-down { color: var(--color-accent); }
.stat-delta .is-up { color: #fb923c; }
@media (max-width: 560px) { .csr { grid-template-columns: 1fr; gap: 0.2rem; } }
.split-legend {
  display: flex; justify-content: space-between; gap: 0.5rem;
  font-size: 0.74rem; color: var(--color-text-muted);
}
.split-legend span:last-child { text-align: right; }

/* === Energy balance panel (app Übersicht) ===
   Rendered by js/energy-balance.js at the foot of the overview. Uses the app's
   own tile language (.stat-card via statTile) + section heading so it matches
   the Bezug/PV sections above; only the split bars + carrier list are bespoke.
   The landing (index.html) keeps its own glassy .home-* card inline until its
   redesign — these app classes are deliberately separate (.balance-*). */
.overview-balance {
  /* Top-align the panel with the rail's #building-search box. #sidebar has a
     1.5rem top padding while the rail list panel has 0.85rem; this negative
     margin cancels that delta so the panel's top edge lines up with the search
     box rather than sitting ~30px below it. */
  margin-top: calc(0.85rem - 1.5rem);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 0.85rem 1rem 1.1rem;
}
/* Four headline figures flow 4→2→1 across as the content area narrows. */
.overview-balance .stat-cards { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); margin-bottom: 1rem; }
/* Green value (no box tint) for the two Strom-Anteil tiles — the key message. */
.stat-card--accent .value { color: var(--color-accent); }

.balance-bars { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1rem, 3vw, 2rem); margin: 0.2rem 0 1.2rem; }
.balance-bars h3 { font-size: 0.86rem; font-weight: 600; margin: 0 0 0.2rem; color: var(--color-text); }
.balance-bars .sub { font-size: 0.76rem; color: var(--color-text-muted); margin-bottom: 0.5rem; }
.balance-carriers-title { font-size: 0.78rem; color: var(--color-text-muted); margin: 0 0 0.6rem; }

@media (max-width: 560px) { .balance-bars { grid-template-columns: 1fr; } }

/* ===================================================================
   Polish pass — purely cosmetic depth & accents to match the landing (index.html).
   Only touches paint properties (background / shadow / border-color /
   transform-on-hover / gradient accents); no box dimensions change, so
   the grid + flex layout stays exactly as tuned.
   =================================================================== */

/* Ambient top-glow on the two main surfaces. background-attachment defaults
   to "scroll" (fixed to the element's box, NOT the viewport), so these glows
   stay anchored at the top of the panel while content scrolls underneath —
   the same radial ambience as the landing page, with no layout impact. */
#sidebar {
  background:
    radial-gradient(900px 440px at 72% -12%, rgba(52, 211, 153, 0.055), transparent 60%),
    radial-gradient(820px 420px at 4% -8%, rgba(79, 140, 255, 0.06), transparent 58%),
    var(--color-surface);
}
#left-rail {
  background:
    radial-gradient(620px 360px at 18% -6%, rgba(79, 140, 255, 0.05), transparent 60%),
    var(--color-surface);
}

/* Lift the header + filter bar off the content with a faint gradient and a
   soft drop shadow (depth, like home's elevated card). */
#header {
  background: linear-gradient(180deg, #1c1f27, var(--color-surface));
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.02), 0 6px 18px rgba(0, 0, 0, 0.28);
}
#filter-panel {
  background: linear-gradient(180deg, var(--color-surface), #15171d);
}

/* Buttons: subtle hover lift; active nav button gets the brand gradient +
   glow instead of a flat fill. */
.btn { transition: background 0.15s, border-color 0.15s, transform 0.15s, box-shadow 0.15s; }
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
/* Active view tab — same tinted recipe as .fp-pill.active / .chart-option.active
   so the whole control language agrees. Home keeps its gradient (it's the doorway). */
.btn-outline.active {
  color: var(--color-bezug);
  background: color-mix(in srgb, var(--color-bezug) 16%, transparent);
  border-color: color-mix(in srgb, var(--color-bezug) 55%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-bezug) 30%, transparent);
}
.btn-outline.active:hover { background: color-mix(in srgb, var(--color-bezug) 22%, transparent); }
/* Home is the doorway back to the polished landing — give it the
   primary→accent gradient as an inviting anchor on the right. */
.btn-home {
  background: linear-gradient(135deg, var(--color-primary), var(--color-accent));
  color: #0f1117; font-weight: 600; border-color: transparent;
  box-shadow: 0 4px 16px rgba(52, 211, 153, 0.22);
}
.btn-home:hover {
  background: linear-gradient(135deg, #3b7aff, #2bbf8a);
  border-color: transparent;
  box-shadow: 0 8px 22px rgba(52, 211, 153, 0.32);
}

/* Stat cards: gentle top-lit gradient + soft elevation, and a hover that
   warms the border and lifts the card. Padding/size untouched. */
.stat-card {
  background: linear-gradient(160deg, #1a1d24, var(--color-bg));
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.stat-card:hover {
  transform: translateY(-1px);
  border-color: rgba(79, 140, 255, 0.35);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.35);
}

/* viz-card: lift the content panels off the surface so they read as cards. */
.viz-card {
  border-radius: var(--radius);
}

/* Section heading: replace the flat blue rule with a gradient that fades
   out — same 2px height, more refined. */
.section-heading {
  border-bottom: 2px solid transparent;
  border-image: linear-gradient(90deg, var(--color-bezug), rgba(79, 140, 255, 0)) 1;
}
.section-heading.pv-heading {
  border-image: linear-gradient(90deg, var(--color-einspeisung), rgba(250, 204, 21, 0)) 1;
}

/* Analyse & Sandbox render their card/section titles as bare <h3>, while
   Übersicht/Vergleich/Detail use .section-heading (uppercase, muted, gradient
   underline). Give those h3 the same heading language so all four tabs read as
   one product. Typography + bottom border only — no box geometry changes. */
.viz-card > h3,
.overview-section > h3 {
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  padding-bottom: 0.25rem;
  border-bottom: 2px solid transparent;
  border-image: linear-gradient(90deg, var(--color-bezug), rgba(79, 140, 255, 0)) 1;
}
/* When a caption (.section-desc) follows the title, drop the rule so the
   underline never splits a title from its own caption. */
.viz-card > h3:has(+ .section-desc),
.overview-section > h3:has(+ .section-desc) {
  border-image: none;
  border-bottom: none;
  padding-bottom: 0;
}

/* ===================================================================
   Micro-interactions, softened DQ badge, and the landing entrance.
   All paint-only (transform / opacity / shadow / color).
   =================================================================== */

/* #42 — list rows & chart pager echo the card/button hover language. */
.ranking-item:hover, .ranking-item.hover {
  box-shadow: 0 3px 12px rgba(0, 0, 0, 0.3);
  transform: translateY(-1px);
}
.chart-page-btn:hover { transform: translateY(-1px); box-shadow: 0 3px 10px rgba(79, 140, 255, 0.28); }
.chart-page-btn:active { transform: translateY(0); }

/* #43 — soften the data-quality badge: translucent fill + ring + diffuse glow
   instead of a hard flat colour with near-black digits. */
.dq-dot-btn--critical {
  background: rgba(248, 113, 113, 0.16); color: #fca5a5;
  box-shadow: inset 0 0 0 1px rgba(248, 113, 113, 0.5), 0 0 12px rgba(248, 113, 113, 0.22);
}
.dq-dot-btn--warning {
  background: rgba(245, 158, 11, 0.16); color: #fcd34d;
  box-shadow: inset 0 0 0 1px rgba(245, 158, 11, 0.5), 0 0 12px rgba(245, 158, 11, 0.2);
}
.dq-dot-btn--info {
  background: rgba(96, 165, 250, 0.16); color: #93c5fd;
  box-shadow: inset 0 0 0 1px rgba(96, 165, 250, 0.5), 0 0 12px rgba(96, 165, 250, 0.2);
}
.dq-dot-btn { transition: box-shadow 0.15s ease, transform 0.15s ease; }
.dq-dot-btn:hover { transform: translateY(-1px); }

/* #41 — entrance when arriving from the landing page (app.html?from=home).
   Header fades; rail + content rise in with a small stagger. Class is added
   only after the Übersicht has rendered, so it animates populated content. */
.enter-home #header { animation: enter-fade 0.5s ease both; }
.enter-home #left-rail { animation: enter-rise 0.55s cubic-bezier(0.22, 1, 0.36, 1) both; animation-delay: 0.04s; }
.enter-home #sidebar { animation: enter-rise 0.6s cubic-bezier(0.22, 1, 0.36, 1) both; animation-delay: 0.12s; }
@keyframes enter-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes enter-rise { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* From-home only: once the rail/content have risen, the Übersicht's own pieces
   animate in — tiles pop (staggered), charts fade, bars grow from the left.
   Scoped to #sidebar so other views aren't touched; one-shot (app.js drops
   .enter-home after the entrance) so it never replays on return. */
.enter-home #sidebar .stat-card { animation: enter-pop 0.45s cubic-bezier(0.22, 1, 0.36, 1) both; }
.enter-home #sidebar .stat-card:nth-child(1) { animation-delay: 0.20s; }
.enter-home #sidebar .stat-card:nth-child(2) { animation-delay: 0.26s; }
.enter-home #sidebar .stat-card:nth-child(3) { animation-delay: 0.32s; }
.enter-home #sidebar .stat-card:nth-child(4) { animation-delay: 0.38s; }
.enter-home #sidebar .stat-card:nth-child(5) { animation-delay: 0.44s; }
.enter-home #sidebar .stat-card:nth-child(6) { animation-delay: 0.50s; }
.enter-home #sidebar .chart-container { animation: enter-fade 0.8s ease both; animation-delay: 0.42s; }
.enter-home #sidebar .csb-fill,
.enter-home #sidebar .balance-bars .split-bar > * {
  transform-origin: left center;
  animation: bar-grow 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
  animation-delay: 0.52s;
}
@keyframes enter-pop { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: none; } }
@keyframes bar-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }

@media (prefers-reduced-motion: reduce) {
  .enter-home #header, .enter-home #left-rail, .enter-home #sidebar,
  .enter-home #sidebar .stat-card, .enter-home #sidebar .chart-container,
  .enter-home #sidebar .csb-fill, .enter-home #sidebar .balance-bars .split-bar > * { animation: none; }
}

/* Szenario pill switch on the Übersicht. The four headline tiles stay put and
   their numbers count (JS); the two split bars regrow from the left. The
   Energieträger list runs its own staged JS transition (reorder → bar widths →
   ghost dim-in), so it is NOT animated here. Scoped to .balance-lower. */
.balance-lower.scenario-anim .split-bar > * {
  transform-origin: left center;
  animation: bar-grow 0.9s cubic-bezier(0.22, 1, 0.36, 1) both;
}
@media (prefers-reduced-motion: reduce) {
  .balance-lower.scenario-anim .split-bar > * { animation: none; }
}
