/* =============================================================================
   Heliotec design-system components + style-guide page chrome.
   All values reference tokens from tokens.css — no hard-coded hex here.
   ============================================================================= */

/* --- Page chrome ---------------------------------------------------------- */
.ds-board {
  /* Ambient background reproduced from the source HTML prototype: a dark base
     (--ds-bg = #0a0d1a) with two soft, fixed radial "glow" blobs below. */
  background: var(--ds-bg);
  color: var(--ds-text);
  font-family: var(--ds-font);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
  margin: 0;
  position: relative;
  overflow-x: hidden;
}
.ds-board::before {
  content: "";
  position: fixed;
  top: -20%;
  left: -10%;
  width: 60%;
  height: 80%;
  background: radial-gradient(ellipse at center, rgba(90, 60, 180, 0.18), transparent 60%);
  pointer-events: none;
  z-index: 0;
}
.ds-board::after {
  content: "";
  position: fixed;
  top: 10%;
  right: -10%;
  width: 50%;
  height: 70%;
  background: radial-gradient(ellipse at center, rgba(40, 80, 200, 0.15), transparent 60%);
  pointer-events: none;
  z-index: 0;
}
.ds-page { max-width: 1280px; margin: 0 auto; padding: 56px 48px 96px; position: relative; z-index: 1; }
.ds-header { margin-bottom: 12px; }
.ds-header h1 { font-size: 32px; font-weight: 700; letter-spacing: -0.8px; margin: 0 0 8px; }
.ds-header p { color: var(--ds-text-dim); font-size: 16px; margin: 0; max-width: 760px; line-height: 1.5; }
.ds-section { margin-top: 56px; }
.ds-section > h2 { font-size: var(--ds-fs-section); font-weight: var(--ds-fw-section); letter-spacing: -0.5px; margin: 0 0 6px; }
.ds-section > .ds-sub { color: var(--ds-text-dim); font-size: 14px; margin: 0 0 18px; }
.ds-eyebrow { font-size: var(--ds-fs-eyebrow); font-weight: 600; letter-spacing: 1.4px; color: var(--ds-text-muted); text-transform: uppercase; margin: 22px 0 12px; }
.ds-card { background: var(--ds-surface); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); border: 1px solid var(--ds-border); border-radius: var(--ds-radius-lg); }

/* --- Colour swatches ------------------------------------------------------ */
.ds-swatch-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; }
.ds-swatch__chip { height: 76px; border-radius: 12px; border: 1px solid var(--ds-border-strong); }
.ds-swatch__name { font-size: 13px; font-weight: 600; margin-top: 8px; }
.ds-swatch__meta { font-size: 12px; color: var(--ds-text-muted); }

/* --- Brand palette ramps -------------------------------------------------- */
.ds-ramp-grid { display: flex; gap: 12px; flex-wrap: wrap; }
.ds-ramp { width: 156px; border-radius: 12px; overflow: hidden; border: 1px solid var(--ds-border-strong); }
.ds-ramp__head { padding: 16px 14px 20px; }
.ds-ramp__role { font-size: 10px; text-transform: uppercase; letter-spacing: 1px; opacity: 0.75; }
.ds-ramp__name { font-size: 13px; font-weight: 700; letter-spacing: 0.4px; margin-top: 2px; }
.ds-ramp__hex { font-size: 11px; opacity: 0.85; margin-top: 2px; }
.ds-ramp__var { font-size: 10.5px; opacity: 0.75; margin-top: 3px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.ds-ramp__cell { padding: 8px 14px; display: flex; flex-direction: column; gap: 1px; }
.ds-ramp__cellhex { font-size: 10.5px; }
.ds-ramp__cellvar { font-size: 9.5px; opacity: 0.7; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }

/* --- Typography specimens ------------------------------------------------- */
.ds-type-list { display: flex; flex-direction: column; }
.ds-type-row { display: flex; align-items: center; justify-content: space-between; gap: 24px; padding: 16px 0; border-bottom: 1px solid var(--ds-border); }
.ds-type-row:last-child { border-bottom: none; }
.ds-type-row .ds-type-spec { font-size: 12px; color: var(--ds-text-muted); white-space: nowrap; }

/* --- Spacing & radius ----------------------------------------------------- */
.ds-scale-cols { display: flex; gap: 80px; flex-wrap: wrap; }
.ds-radius-row { display: flex; gap: 16px; align-items: flex-end; }
.ds-radius-tile { width: 76px; height: 76px; background: rgba(234, 246, 114, 0.12); border: 1px solid rgba(234, 246, 114, 0.5); }
.ds-radius-label { font-size: 12px; color: var(--ds-text-muted); margin-top: 8px; }
.ds-space-row { display: flex; align-items: center; gap: 14px; margin-bottom: 10px; }
.ds-space-bar { height: 18px; background: var(--ds-accent); border-radius: 3px; }
.ds-space-label { font-size: 12px; color: var(--ds-text-dim); }

/* --- Iconography ---------------------------------------------------------- */
.ds-icon-row { display: flex; gap: 16px; flex-wrap: wrap; }
.ds-icon-tile { display: flex; flex-direction: column; align-items: center; gap: 10px; width: 120px; }
.ds-icon-tile .ds-icon-box { width: 56px; height: 56px; border-radius: 12px; background: var(--ds-surface); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); border: 1px solid var(--ds-border); display: flex; align-items: center; justify-content: center; color: var(--ds-text-dim); font-size: 22px; }
.ds-icon-tile span { font-size: 12px; color: var(--ds-text-muted); }

/* --- Component demo layout ------------------------------------------------ */
.ds-demo { display: flex; flex-wrap: wrap; gap: 16px; align-items: flex-start; }
.ds-demo--stack { flex-direction: column; }
.ds-usage { font-size: 12px; color: var(--ds-text-muted); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; margin: 6px 0 0; }

/* =============================================================================
   Components
   ============================================================================= */

/* CountChip */
.ds-count-chip { display: inline-flex; align-items: center; padding: 1px 8px; border-radius: var(--ds-radius-pill); background: rgba(255, 255, 255, 0.06); font-size: var(--ds-fs-eyebrow); font-weight: 600; color: var(--ds-text-muted); }
.ds-count-chip--active { background: rgba(234, 246, 114, 0.16); color: var(--ds-accent); }

/* Status dot helpers */
.ds-dot--alert { background: var(--ds-alert); }
.ds-dot--warning { background: var(--ds-warning); }
.ds-dot--positive { background: var(--ds-positive); }

/* RagPill */
.ds-rag-pill { display: inline-flex; align-items: center; gap: 8px; padding: 5px 11px 5px 8px; border-radius: var(--ds-radius-pill); font-size: var(--ds-fs-eyebrow); font-weight: 600; letter-spacing: 1.2px; text-transform: uppercase; }
.ds-rag-pill__dot { width: 7px; height: 7px; border-radius: 50%; }
.ds-rag-pill--alert { background: rgba(255, 106, 97, 0.12); color: var(--ds-alert-soft); }
.ds-rag-pill--alert .ds-rag-pill__dot { background: var(--ds-alert); }
.ds-rag-pill--warning { background: rgba(243, 168, 38, 0.12); color: var(--ds-warning-soft); }
.ds-rag-pill--warning .ds-rag-pill__dot { background: var(--ds-warning); }
.ds-rag-pill--positive { background: rgba(108, 212, 116, 0.10); color: var(--ds-positive-soft); }
.ds-rag-pill--positive .ds-rag-pill__dot { background: var(--ds-positive); }
.ds-rag-pill--grey { background: rgba(255, 255, 255, 0.05); color: var(--ds-text-muted); }
.ds-rag-pill--grey .ds-rag-pill__dot { background: var(--ds-tech); }

/* FilterPill */
.ds-filter-pill { display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px 6px 10px; border-radius: var(--ds-radius-pill); background: rgba(255, 255, 255, 0.03); border: 1px solid var(--ds-border-strong); color: var(--ds-text-dim); font-size: 12.5px; font-weight: 500; }
.ds-filter-pill--active { background: rgba(234, 246, 114, 0.08); border-color: rgba(234, 246, 114, 0.3); color: var(--ds-accent); }
.ds-filter-pill__dot { width: 7px; height: 7px; border-radius: 50%; }

/* DropdownControl */
.ds-dropdown { display: inline-flex; align-items: center; gap: 10px; padding: 8px 14px 8px 16px; border-radius: var(--ds-radius-md); background: rgba(255, 255, 255, 0.03); border: 1px solid var(--ds-border-strong); font-size: var(--ds-fs-secondary); }
.ds-dropdown__kicker { font-size: var(--ds-fs-eyebrow); letter-spacing: 1px; text-transform: uppercase; color: var(--ds-text-muted); }
.ds-dropdown__value { font-weight: 500; color: var(--ds-text); }
.ds-dropdown__caret { font-size: 9px; color: var(--ds-text-dim); transition: transform 0.15s; }

/* DropdownControl — interactive variant (menu wired up by dropdown_control.js) */
.ds-dropdown--interactive { position: relative; display: inline-block; padding: 0; border: 0; background: transparent; }
.ds-dropdown__trigger { display: inline-flex; align-items: center; gap: 10px; padding: 8px 14px 8px 16px; border-radius: var(--ds-radius-md); background: rgba(255, 255, 255, 0.03); border: 1px solid var(--ds-border-strong); font-size: var(--ds-fs-secondary); font-family: var(--ds-font); color: var(--ds-text); cursor: pointer; transition: background 0.15s, border-color 0.15s; }
.ds-dropdown__trigger:hover { background: rgba(255, 255, 255, 0.07); border-color: var(--ds-border-strong); }
.ds-dropdown__trigger:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }
/* When open, lift the whole control into its own stacking context above sibling
   cards/charts so the menu is unambiguously on top for paint AND hit-testing. */
.ds-dropdown--interactive.is-open { z-index: 1000; }
.ds-dropdown--interactive.is-open .ds-dropdown__caret { transform: rotate(180deg); }
.ds-dropdown__menu { position: absolute; top: calc(100% + 6px); right: 0; min-width: 100%; max-height: 320px; overflow-y: auto; margin: 0; padding: 6px; list-style: none; z-index: 40; background: var(--ds-surface-card-solid); border: 1px solid var(--ds-border-strong); border-radius: var(--ds-radius-md); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45); display: none; }
.ds-dropdown--interactive.is-open .ds-dropdown__menu { display: block; }
/* Group heading inside the menu (e.g. "Rolling Window" / "Calendar Month").
   Rendered for `{'header': ...}` items — never selectable, so it deliberately
   carries neither .ds-dropdown__item nor a cursor. */
.ds-dropdown__group { padding: 10px 12px 4px; font-size: var(--ds-fs-eyebrow); letter-spacing: 1px; text-transform: uppercase; color: var(--ds-text-muted); white-space: nowrap; }
.ds-dropdown__group:first-child { padding-top: 4px; }
.ds-dropdown__item { padding: 8px 12px; border-radius: var(--ds-radius-sm); font-size: var(--ds-fs-secondary); color: var(--ds-text-dim); white-space: nowrap; cursor: pointer; }
.ds-dropdown__item:hover, .ds-dropdown__item.is-active { background: rgba(255, 255, 255, 0.07); color: var(--ds-text); }
.ds-dropdown__item.is-selected { color: var(--ds-accent); background: rgba(234, 246, 114, 0.08); }

/* MultiSelect — searchable multi-select (e.g. Carbon page site switcher).
   Behaviour wired up by multi_select.js; emits ds:multiselect-change. */
.ds-multiselect { position: relative; display: inline-block; }
.ds-multiselect.is-open { z-index: 1000; }
.ds-multiselect__trigger { display: inline-flex; align-items: center; gap: 10px; max-width: 360px; padding: 9px 14px; border-radius: var(--ds-radius-md); background: rgba(255, 255, 255, 0.03); border: 1px solid var(--ds-border-strong); font-size: var(--ds-fs-secondary); font-family: var(--ds-font); color: var(--ds-text); cursor: pointer; transition: background 0.15s, border-color 0.15s; }
.ds-multiselect__trigger:hover { background: rgba(255, 255, 255, 0.07); border-color: var(--ds-border-strong); }
.ds-multiselect__trigger:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }
.ds-multiselect__kicker { font-size: var(--ds-fs-eyebrow); letter-spacing: 1.1px; text-transform: uppercase; color: var(--ds-text-muted); }
.ds-multiselect__value { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-multiselect__caret { margin-left: 2px; font-size: 9px; color: var(--ds-text-dim); transition: transform 0.18s; }
.ds-multiselect.is-open .ds-multiselect__caret { transform: rotate(180deg); }
.ds-multiselect__menu { position: absolute; top: calc(100% + 6px); right: 0; min-width: 320px; z-index: 40; padding: 8px; background: var(--ds-surface-card-solid); border: 1px solid var(--ds-border-strong); border-radius: var(--ds-radius-lg); box-shadow: 0 16px 40px rgba(0, 0, 0, 0.55); display: none; }
.ds-multiselect.is-open .ds-multiselect__menu { display: block; }
.ds-multiselect__search { padding: 2px 2px 8px; }
.ds-multiselect__search-input { width: 100%; padding: 9px 11px; background: rgba(255, 255, 255, 0.04); border: 1px solid var(--ds-border-strong); border-radius: var(--ds-radius-sm); color: var(--ds-text); font-family: var(--ds-font); font-size: var(--ds-fs-secondary); outline: none; }
.ds-multiselect__search-input:focus { border-color: var(--ds-accent); }
.ds-multiselect__search-input::placeholder { color: var(--ds-text-muted); }
.ds-multiselect__count { padding: 2px 6px 8px; font-size: var(--ds-fs-eyebrow); letter-spacing: 1.2px; text-transform: uppercase; color: var(--ds-text-muted); font-weight: 600; }
.ds-multiselect__list { max-height: 340px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.ds-multiselect__item { display: flex; align-items: center; gap: 11px; width: 100%; padding: 7px 10px; border: none; border-radius: var(--ds-radius-sm); background: transparent; font-family: var(--ds-font); font-size: var(--ds-fs-secondary); color: var(--ds-text); text-align: left; cursor: pointer; }
.ds-multiselect__item:hover { background: rgba(255, 255, 255, 0.05); }
.ds-multiselect__item.is-selected { background: rgba(234, 246, 114, 0.06); }
.ds-multiselect__dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.ds-multiselect__dot--alert { background: var(--ds-alert); box-shadow: 0 0 6px var(--ds-alert); }
.ds-multiselect__dot--warning { background: var(--ds-warning); box-shadow: 0 0 6px var(--ds-warning); }
.ds-multiselect__dot--positive { background: var(--ds-positive); box-shadow: 0 0 6px var(--ds-positive); }
.ds-multiselect__dot--grey { background: var(--ds-text-muted); }
.ds-multiselect__dot--all { background: var(--ds-accent); box-shadow: 0 0 6px rgba(234, 246, 114, 0.4); }
.ds-multiselect__text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.ds-multiselect__name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-multiselect__item.is-selected .ds-multiselect__name { color: var(--ds-accent); }
.ds-multiselect__sub { font-size: 11px; color: var(--ds-text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-multiselect__check { width: 14px; height: 14px; flex: none; color: var(--ds-accent); opacity: 0; }
.ds-multiselect__item.is-selected .ds-multiselect__check { opacity: 1; }
.ds-multiselect__item--disabled { opacity: 0.4; cursor: not-allowed; }
.ds-multiselect__item--disabled:hover { background: transparent; }
.ds-multiselect__empty { padding: 16px 12px; text-align: center; font-size: var(--ds-fs-secondary); color: var(--ds-text-muted); }

/* AiBadge */
.ds-ai-badge { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 7px; background: rgba(234, 246, 114, 0.13); border: 1px solid rgba(234, 246, 114, 0.25); color: var(--ds-accent); font-size: 13px; }

/* MetricBlock */
.ds-metric { display: flex; flex-direction: column; gap: 10px; min-width: 280px; }
.ds-metric__top { display: flex; align-items: flex-start; gap: 12px; }
.ds-metric__value { font-size: var(--ds-fs-metric); font-weight: var(--ds-fw-metric); letter-spacing: -1.3px; line-height: 1.05; }
.ds-metric__unit { font-size: 0.4em; font-weight: 500; letter-spacing: 0; color: var(--ds-text-muted); margin-left: 6px; }
.ds-metric__chip { align-self: center; padding: 5px 11px; border-radius: var(--ds-radius-pill); background: rgba(234, 246, 114, 0.08); border: 1px solid rgba(234, 246, 114, 0.18); color: var(--ds-accent); font-size: var(--ds-fs-secondary); font-weight: 500; }
.ds-metric__label { font-size: var(--ds-fs-body); color: var(--ds-text-dim); }
.ds-metric__label strong { color: var(--ds-text); font-weight: 500; }
.ds-metric__delta { display: inline-flex; align-items: center; gap: 7px; font-size: 14px; font-weight: 500; }
.ds-metric__glyph { font-size: 10px; }
.ds-delta--down { color: var(--ds-positive); }
.ds-delta--up { color: var(--ds-alert); }
/* Unchanged vs previous period (no colour / no direction) */
.ds-delta--neutral { color: var(--ds-text-muted); }
/* No comparable previous period — muted, no arrow */
.ds-delta--none { color: var(--ds-text-muted); font-style: italic; }

/* Loading state — a small spinner replaces the number while a metric tile refetches
   (e.g. changing the header Period filter on the Site / Carbon pages). The value text
   goes transparent and a ring spins where it was; the chip/delta hide so stale figures
   don't linger. The spinner fades in over ~0.25s so a fast response shows only a faint
   hint rather than a hard flash. */
.ds-metric.is-loading .ds-metric__value {
  color: transparent;
  position: relative;
}
.ds-metric.is-loading .ds-metric__value::after {
  content: '';
  position: absolute;
  left: 2px;
  top: 50%;
  width: 22px;
  height: 22px;
  margin-top: -11px;
  border: 2px solid var(--ds-border-strong);
  border-top-color: var(--ds-text-dim);
  border-radius: 50%;
  animation: ds-metric-spin 0.7s linear infinite, ds-metric-spin-in 0.25s ease-out;
}
.ds-metric.is-loading .ds-metric__chip,
.ds-metric.is-loading .ds-metric__delta {
  visibility: hidden;
}
@keyframes ds-metric-spin {
  to { transform: rotate(360deg); }
}
@keyframes ds-metric-spin-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* StatusBar (proportional RAG segments — e.g. Sites by status).
   Display-only by default; interactive (clickable/filtering) styling is
   dormant under .ds-status-bar--interactive until the page-wide filtering
   pattern is decided. */
.ds-status-bar { display: flex; height: 56px; border-radius: var(--ds-radius-md); overflow: hidden; gap: 2px; }
.ds-status-bar__seg { display: flex; align-items: center; justify-content: center; gap: 10px; min-width: 0; padding: 0 12px; border: 0; font-family: var(--ds-font); color: var(--ds-bg); transition: filter 0.15s, opacity 0.15s; }
.ds-status-bar--interactive .ds-status-bar__seg { cursor: pointer; }
.ds-status-bar--interactive .ds-status-bar__seg:hover { filter: brightness(1.08); }
.ds-status-bar--interactive .ds-status-bar__seg:focus-visible { outline: 2px solid var(--ds-text); outline-offset: -3px; }
.ds-status-bar__num { font-size: 22px; font-weight: 700; letter-spacing: -0.5px; line-height: 1; }
.ds-status-bar__name { font-size: var(--ds-fs-meta); font-weight: 600; letter-spacing: 1.6px; text-transform: uppercase; opacity: 0.85; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-status-bar__seg--alert { background: var(--ds-alert); }
.ds-status-bar__seg--warning { background: var(--ds-warning); }
.ds-status-bar__seg--positive { background: var(--ds-positive); }
.ds-status-bar__seg--grey { background: var(--ds-tech); color: var(--ds-text); }
/* Selected/filter state (dormant) — page toggles .has-filter on the bar +
   .is-active on a seg once interactive filtering is enabled. */
.ds-status-bar--interactive.has-filter .ds-status-bar__seg:not(.is-active) { opacity: 0.4; }
.ds-status-bar--interactive .ds-status-bar__seg.is-active { outline: 2px solid var(--ds-text); outline-offset: -3px; }
/* Empty state — no live status data */
.ds-status-bar__placeholder { display: flex; align-items: center; height: 56px; padding: 0 16px; border-radius: var(--ds-radius-md); border: 1px dashed var(--ds-border-strong); color: var(--ds-text-muted); font-size: var(--ds-fs-secondary); }

/* BreakdownBar (avoidable-spend Out-of-Hours / Startup / Shutdown split —
   stacked bar + one row per category). Shared by the client Site Overview
   header tile and the Org Overview headline. Segment colour is fixed per
   category (red/yellow/blue), not RAG-driven like StatusBar above, so each
   category reads the same wherever the bar appears. Missing-state
   (.ds-breakdown__prompt) swaps in for Startup/Shutdown when a site has no
   business hours configured — never rendered as £0 rows. Tooltip text is the
   native `title` attribute on both the segment and its row — no custom
   JS/CSS popover, so the component owns no interactive behaviour. */
.ds-breakdown { display: flex; flex-direction: column; gap: var(--ds-space-2); margin-top: var(--ds-space-3); }
.ds-breakdown__bar { display: flex; height: 10px; border-radius: var(--ds-radius-sm); overflow: hidden; gap: 2px; background: rgba(255, 255, 255, 0.05); }
.ds-breakdown__seg { min-width: 4px; }
.ds-breakdown__rows { display: flex; flex-direction: column; gap: 6px; }
.ds-breakdown__row { display: flex; align-items: center; gap: 8px; font-size: var(--ds-fs-meta); color: var(--ds-text-dim); cursor: default; }
.ds-breakdown__swatch { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.ds-breakdown__row-label { flex: 1; min-width: 0; color: var(--ds-text); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ds-breakdown__row-cost { font-weight: 600; color: var(--ds-text); }
.ds-breakdown__row-pct { color: var(--ds-text-dim); min-width: 32px; text-align: right; }
.ds-breakdown__row-alerts { color: var(--ds-text-muted); white-space: nowrap; }
/* Stacked, not side-by-side: the prompt sentence is long and the card it sits
   in is narrow, so a row layout wrapped the text to five lines with the CTA
   floating beside the middle of them. On its own line the CTA reads as the
   next thing to do rather than an aside. */
.ds-breakdown__prompt {
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  padding: 8px 10px; border: 1px dashed var(--ds-border-strong); border-radius: var(--ds-radius-sm);
  font-size: var(--ds-fs-meta); color: var(--ds-text-dim);
}
.ds-breakdown__prompt-text { min-width: 0; }
.ds-breakdown__prompt-cta { color: var(--ds-accent); font-weight: 600; white-space: nowrap; text-decoration: none; }
/* Button variant (Site Overview PR 3 — CTA opens the business-hours modal in
   place instead of linking out) resets native <button> chrome so it looks
   identical to the <a> variant above. */
button.ds-breakdown__prompt-cta { background: none; border: none; padding: 0; font: inherit; cursor: pointer; }
.ds-breakdown__prompt-cta:hover { text-decoration: underline; }
/* Hover/focus tooltip (design_system/js/breakdown_tooltip.js). Replaces the
   native `title`: styled to match the consistency chart's tooltip on the same
   page, instant rather than after an OS delay, and reachable by keyboard.
   The tip is `position: fixed` so it can sit ABOVE the bar: the bar is the
   first thing in .ds-breakdown, and .site-stat-card sets overflow:hidden to
   clip its accent gradient to the corner radius — an absolutely positioned
   tip would be cut off the instant it rose above the bar. */
.ds-breakdown__seg, .ds-breakdown__row { cursor: default; }
.ds-breakdown__seg:focus-visible, .ds-breakdown__row:focus-visible {
  outline: 2px solid var(--ds-accent); outline-offset: 2px;
}
.ds-breakdown__tip {
  position: fixed; z-index: 60; display: none; min-width: 140px; max-width: 260px;
  background: var(--ds-bg); border: 1px solid var(--ds-border-strong);
  border-radius: var(--ds-radius-md); padding: 9px 11px; pointer-events: none;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45);
}
.ds-breakdown__tip.is-visible { display: block; }
.ds-breakdown__tip-head { display: block; font-size: var(--ds-fs-meta); font-weight: 700; color: var(--ds-text); }
.ds-breakdown__tip-line { display: block; font-size: var(--ds-fs-meta); color: var(--ds-text-dim); margin-top: 3px; }

/* Hide stale segments/rows during a header refetch (mirrors .ds-metric.is-loading
   above) — the AJAX period-refresh flow replaces the whole fragment anyway, but
   this avoids a flash of the pre-fetch breakdown while the request is in flight. */
.ds-metric.is-loading .ds-breakdown { visibility: hidden; }
/* Org Overview-only footer line ("Startup & shutdown tracked for X of Y
   sites" + an optional "add business hours for N more" action) rendered
   below the breakdown_bar by client/includes/_org_avoidable_card.html — not
   part of the breakdown_bar tag itself (the site-level widget has no
   equivalent footer, since coverage there is a per-site binary shown via
   the prompt instead). Reuses .ds-breakdown__prompt-cta for the action link
   so both CTA styles match. */
.ds-breakdown__footer {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-top: 2px; padding-top: 8px; border-top: 1px solid var(--ds-border);
  font-size: var(--ds-fs-meta); color: var(--ds-text-muted);
}
.ds-breakdown__footer .ds-breakdown__prompt-cta { flex-shrink: 0; }

/* InsightCard (translucent; lightbulb + impact header row, no accent bar) */
.ds-insight-card { position: relative; border: 1px solid var(--ds-border); border-radius: var(--ds-radius-lg); overflow: hidden; width: 100%; }
.ds-insight-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: linear-gradient(90deg, transparent, var(--ds-accent), transparent); opacity: 0.3; z-index: 1; }
.ds-insight-card__body { background: var(--ds-surface); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); padding: 16px; display: flex; flex-direction: column; gap: 8px; }
.ds-insight-card__top { display: flex; align-items: center; gap: 8px; min-height: 22px; }
.ds-insight-card__icon { color: var(--ds-accent); flex: none; line-height: 0; }
.ds-insight-card__kicker { font-size: 12px; font-weight: 600; letter-spacing: 0.2px; color: var(--ds-accent); }
.ds-insight-card__impact { margin-left: auto; font-size: 18px; font-weight: 700; letter-spacing: -0.4px; color: var(--ds-accent); }
.ds-insight-card__unit { font-size: 12px; color: var(--ds-text-muted); margin-left: 3px; }
.ds-insight-card__headline { font-size: 14px; font-weight: 600; line-height: 1.35; }
.ds-insight-card__text { font-size: 12.5px; color: var(--ds-text-dim); line-height: 1.45; }
.ds-insight-card__action { font-size: 13px; font-weight: 500; color: var(--ds-positive); }

/* EventCard (translucent, left status accent) */
.ds-event-card { border-radius: var(--ds-radius-md); overflow: hidden; width: 340px; }
.ds-event-card__body { background: var(--ds-surface); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); border: 1px solid var(--ds-border); border-left: 3px solid var(--ds-alert); padding: 14px 16px 12px; display: flex; flex-direction: column; gap: 10px; }
.ds-event-card--alert .ds-event-card__body { border-left-color: var(--ds-alert); }
.ds-event-card--warning .ds-event-card__body { border-left-color: var(--ds-warning); }
.ds-event-card--positive .ds-event-card__body { border-left-color: var(--ds-positive); }
.ds-event-card__top { display: flex; align-items: center; justify-content: space-between; }
.ds-event-card__badge { font-size: 10px; font-weight: 600; letter-spacing: 1.3px; text-transform: uppercase; }
.ds-event-card--alert .ds-event-card__badge { color: var(--ds-alert-soft); }
.ds-event-card--warning .ds-event-card__badge { color: var(--ds-warning-soft); }
.ds-event-card__time { font-size: 11px; color: var(--ds-text-muted); }
.ds-event-card__headline { font-size: 13.5px; font-weight: 500; line-height: 1.35; }
.ds-event-card__bottom { display: flex; align-items: flex-end; justify-content: space-between; gap: 10px; }
.ds-event-card__stats { display: flex; gap: 12px; }
.ds-stat { display: flex; flex-direction: column; font-size: 11px; color: var(--ds-text-dim); }

/* NoticeBanner (inline informational strip; icon + title + body, left-accent tint by tone) */
.ds-notice-banner { display: flex; align-items: flex-start; gap: var(--ds-space-3); padding: var(--ds-space-3) var(--ds-space-4); border-radius: var(--ds-radius-md); border: 1px solid var(--ds-border); }
.ds-notice-banner__icon { flex: none; line-height: 0; margin-top: 2px; font-size: 15px; }
.ds-notice-banner__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.ds-notice-banner__title { font-size: var(--ds-fs-secondary); font-weight: 600; color: var(--ds-text); }
.ds-notice-banner__text { font-size: var(--ds-fs-secondary); color: var(--ds-text-dim); line-height: 1.45; }
.ds-notice-banner--warning { background: rgba(243, 168, 38, 0.10); border-color: rgba(243, 168, 38, 0.3); }
.ds-notice-banner--warning .ds-notice-banner__icon { color: var(--ds-warning); }
.ds-notice-banner--alert { background: rgba(255, 106, 97, 0.10); border-color: rgba(255, 106, 97, 0.3); }
.ds-notice-banner--alert .ds-notice-banner__icon { color: var(--ds-alert); }
.ds-notice-banner--positive { background: rgba(108, 212, 116, 0.10); border-color: rgba(108, 212, 116, 0.3); }
.ds-notice-banner--positive .ds-notice-banner__icon { color: var(--ds-positive); }
.ds-stat strong { font-size: 12.5px; font-weight: 600; color: var(--ds-text); }
.ds-stat--cost strong { color: var(--ds-accent); }
.ds-label-pill { display: inline-flex; align-items: center; gap: 5px; padding: 4px 9px; border-radius: var(--ds-radius-pill); border: 1px solid var(--ds-border-strong); font-size: 10.5px; font-weight: 500; color: var(--ds-text-muted); white-space: nowrap; }
.ds-label-pill__dot { width: 6px; height: 6px; border-radius: 50%; }
.ds-label-pill--empty { border-style: dashed; }

/* Bars (shared by equipment & device rows) */
.ds-bar-track { height: 10px; background: rgba(255, 255, 255, 0.05); border-radius: 5px; overflow: hidden; }
.ds-bar-track--sm { height: 6px; border-radius: 3px; }
.ds-bar-fill { height: 100%; background: var(--ds-voltage); border-radius: inherit; }

/* SiteTableRow */
.ds-site-row { display: grid; grid-template-columns: 96px minmax(180px, 1fr) repeat(5, 130px); gap: 24px; align-items: center; padding: 18px 28px; background: var(--ds-surface); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); border: 1px solid var(--ds-border); border-radius: var(--ds-radius-md); }
.ds-site-row__name { font-size: 14px; font-weight: 500; }
.ds-site-row__addr { font-size: 12px; color: var(--ds-text-muted); margin-top: 3px; }
.ds-site-row__num { text-align: right; font-size: 13.5px; font-weight: 500; }

/* EquipmentGroupRow */
.ds-equip-row { display: grid; grid-template-columns: 220px 1fr 160px 22px; gap: 24px; align-items: center; padding: 18px 24px; background: var(--ds-surface); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); border: 1px solid var(--ds-border); border-radius: var(--ds-radius-md); }
.ds-equip-row__name { display: flex; align-items: center; gap: 10px; font-size: 15px; font-weight: 600; letter-spacing: -0.2px; }
.ds-equip-row__bar { display: flex; flex-direction: column; gap: 8px; }
.ds-equip-row__pct { font-size: 11px; font-weight: 500; color: var(--ds-text-dim); }
.ds-equip-row__vals { text-align: right; }
.ds-equip-row__cost { font-size: 19px; font-weight: 700; letter-spacing: -0.4px; }
.ds-equip-row__kwh { font-size: 12px; color: var(--ds-text-muted); }
.ds-equip-row__chev { color: var(--ds-text-muted); }

/* DeviceRow */
.ds-device-row { display: grid; grid-template-columns: 188px 1fr 160px 22px; gap: 24px; align-items: center; padding: 11px 12px; border-radius: var(--ds-radius-sm); background: rgba(0, 0, 0, 0.14); }
.ds-device-row__name { display: flex; align-items: center; gap: 9px; font-size: 13.5px; font-weight: 500; }
.ds-device-row__dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(74, 82, 242, 0.65); }
.ds-device-row__vals { text-align: right; }
.ds-device-row__cost { font-size: 13.5px; font-weight: 600; }
.ds-device-row__kwh { font-size: 11px; color: var(--ds-text-muted); margin-left: 7px; }
.ds-device-row__chev { color: var(--ds-text-muted); text-align: center; }

/* =============================================================================
   Interaction states — CSS only. These define how interactive components look
   on hover / focus / active / selected / disabled. Actual behaviour (opening
   menus, filtering, selecting) lives in the product, not in this reference.
   Paired `.is-hover` / `.is-selected` / `.is-disabled` classes let the style
   guide show each state statically. `:focus-visible` styles apply once the app
   makes the element focusable.
   ============================================================================= */
.ds-filter-pill,
.ds-dropdown,
.ds-insight-card,
.ds-event-card,
.ds-site-row,
.ds-equip-row,
.ds-device-row {
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.05s;
}

.ds-filter-pill:hover,
.ds-filter-pill.is-hover { background: rgba(255, 255, 255, 0.07); border-color: var(--ds-border-strong); color: var(--ds-text); }
.ds-filter-pill.is-selected { background: rgba(234, 246, 114, 0.08); border-color: rgba(234, 246, 114, 0.3); color: var(--ds-accent); }

.ds-dropdown:hover,
.ds-dropdown.is-hover { background: rgba(255, 255, 255, 0.07); }

.ds-insight-card:hover .ds-insight-card__body,
.ds-insight-card.is-hover .ds-insight-card__body,
.ds-event-card:hover .ds-event-card__body,
.ds-event-card.is-hover .ds-event-card__body { background: var(--ds-surface-hover); }
.ds-insight-card__action:hover { text-decoration: underline; }

.ds-site-row:hover,
.ds-site-row.is-hover,
.ds-equip-row:hover,
.ds-equip-row.is-hover,
.ds-device-row:hover,
.ds-device-row.is-hover { background: var(--ds-surface-hover); }

.ds-site-row.is-selected,
.ds-equip-row.is-selected,
.ds-device-row.is-selected { border-color: rgba(234, 246, 114, 0.4); box-shadow: inset 0 0 0 1px rgba(234, 246, 114, 0.25); }

.ds-filter-pill:active,
.ds-dropdown:active,
.ds-site-row:active,
.ds-equip-row:active,
.ds-device-row:active { transform: translateY(1px); }

.ds-filter-pill:focus-visible,
.ds-dropdown:focus-visible,
.ds-insight-card:focus-visible,
.ds-event-card:focus-visible,
.ds-site-row:focus-visible,
.ds-equip-row:focus-visible,
.ds-device-row:focus-visible { outline: 2px solid var(--ds-accent); outline-offset: 2px; }

.is-disabled,
[aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; pointer-events: none; }

/* Portal — Site Performance table + EPC band.
   Shared across portal pages (Overview, Carbon, Site Overview); lifted here from
   the page <style> blocks so the "Site Performance" table is a single reusable
   component. Token-driven; not ds-prefixed (legacy portal class names kept so
   existing markup/JS is unchanged). */
.perf-card { position: relative; overflow: hidden; background: var(--ds-surface-card); border: 1px solid var(--ds-border); border-radius: var(--ds-radius-xl); }
.perf-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: linear-gradient(90deg, transparent, var(--ds-accent), transparent); opacity: 0.3; z-index: 1; }
.perf-card__header { display: flex; align-items: center; justify-content: space-between; gap: var(--ds-space-4); padding: 20px 28px; border-bottom: 1px solid var(--ds-border); flex-wrap: wrap; }
.perf-card__title { font-size: var(--ds-fs-panel); font-weight: var(--ds-fw-panel); letter-spacing: -0.3px; color: var(--ds-text); }
.perf-card__sub { font-size: var(--ds-fs-secondary); color: var(--ds-text-muted); margin-top: 4px; }
.perf-card__controls { display: flex; align-items: center; gap: var(--ds-space-2); flex-wrap: wrap; }
.perf-filters { display: flex; align-items: center; gap: var(--ds-space-2); flex-wrap: wrap; }
.perf-card__divider { width: 1px; height: 22px; background: var(--ds-border-strong); margin: 0 4px; }
.perf-card__table-wrap { overflow-x: auto; }

.perf-table { width: 100%; border-collapse: collapse; min-width: 920px; }
.perf-th { text-align: left; padding: 12px 12px; font-size: var(--ds-fs-eyebrow); font-weight: 500; text-transform: uppercase; letter-spacing: 0.6px; color: var(--ds-text-muted); background: rgba(255, 255, 255, 0.015); border-bottom: 1px solid var(--ds-border); white-space: nowrap; cursor: pointer; user-select: none; }
.perf-th:first-child { padding-left: 20px; }
.perf-th:last-child { padding-right: 20px; }
.perf-th--num { text-align: right; }
.perf-th:hover { color: var(--ds-text-dim); }
.perf-th.sort-active { color: var(--ds-text); }
.perf-th.sort-active .sort-indicator { color: var(--ds-accent); }

.perf-table tbody tr { border-bottom: 1px solid var(--ds-border); transition: background 0.12s; cursor: pointer; }
.perf-table tbody tr:last-child { border-bottom: none; }
.perf-table tbody tr:hover { background: rgba(255, 255, 255, 0.025); }
.perf-table td { padding: 16px 12px; font-size: 14px; vertical-align: middle; color: var(--ds-text); }
.perf-table td:first-child { padding-left: 20px; }
.perf-table td:last-child { padding-right: 20px; }
.perf-table td.num { text-align: right; }

.perf-site__name { color: var(--ds-text); font-weight: 500; font-size: 13.5px; }
.perf-site__addr { color: var(--ds-text-muted); font-size: 12px; margin-top: 3px; }
.perf-site__reason { font-style: italic; }
.perf-cell__primary--empty { color: var(--ds-text-muted); font-weight: 400; }
/* Shown in place of rows when a status filter matches no sites for the month.
   JS sets an inline height equal to three normal rows; min-height is a fallback. */
.perf-empty-cell { text-align: center; vertical-align: middle; min-height: 198px; color: var(--ds-text-dim); font-size: 13px; }

.perf-cell { display: inline-flex; flex-direction: column; align-items: flex-end; gap: 3px; font-variant-numeric: tabular-nums; }
.perf-cell__primary { color: var(--ds-text); font-weight: 500; font-size: 13.5px; }
.perf-cell__sub { color: var(--ds-text-muted); font-size: 11px; }
.perf-change { display: inline-flex; align-items: center; gap: 3px; font-size: 11px; color: var(--ds-text-muted); font-variant-numeric: tabular-nums; }
.perf-change--up { color: var(--ds-alert); }
.perf-change--down { color: var(--ds-positive); }
.perf-change--flat { color: var(--ds-text-muted); }

.perf-card__footer { display: flex; justify-content: space-between; align-items: center; padding: 16px 28px; border-top: 1px solid var(--ds-border); font-size: 12px; color: var(--ds-text-muted); }

/* EPC asset rating band pill — used via templates/client/_epc_band_pill.html and
   rendered inline by the Overview / Carbon site tables. Colours follow GOV.UK. */
.epc-band { display: inline-block; border-radius: 4px; font-weight: 700; line-height: 1; text-align: center; letter-spacing: 0.5px; }
.epc-band-sm { padding: 2px 8px; font-size: 11px; min-width: 24px; }
.epc-band-lg { padding: 8px 16px; font-size: 22px; min-width: 44px; margin-top: 2px; }

/* TopBar — full-bleed, sharp-cornered portal header (logo · tenant · nav). Mirrors the
   prototype's nav.topbar. Used by the client portal base (templates/client/base_client.html)
   and showcased via the portal_topbar inclusion tag on /design-guide/. */
.ds-topbar { position: relative; z-index: 10; display: flex; align-items: center; padding: 20px 48px; background: rgba(8, 10, 22, 0.85); -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px); border-bottom: 1px solid var(--ds-border); border-radius: 0; }
.ds-topbar__brand { display: flex; align-items: center; gap: 20px; }
.ds-topbar__logo { height: 32px; width: auto; object-fit: contain; display: block; }
.ds-topbar__wordmark { font-size: 22px; font-weight: 700; letter-spacing: -0.5px; color: var(--ds-energy); }
.ds-topbar__divider { width: 1px; height: 22px; background: var(--ds-border-strong); }
.ds-topbar__tenant { font-size: 15px; font-weight: 500; color: var(--ds-text); letter-spacing: -0.1px; }
.ds-topbar__nav { margin-left: auto; display: flex; gap: 32px; align-items: center; }
.ds-topbar__link { font-size: 14px; color: var(--ds-text-dim); text-decoration: none; padding: 4px 0; position: relative; white-space: nowrap; transition: color 0.2s; cursor: pointer; }
.ds-topbar__link:hover { color: var(--ds-text); }
.ds-topbar__link--active { color: var(--ds-text); font-weight: 500; }
.ds-topbar__link--active::after { content: ''; position: absolute; bottom: -6px; left: 0; right: 0; height: 2px; background: var(--ds-energy); border-radius: 1px; box-shadow: 0 0 8px rgba(234, 246, 114, 0.35); }
@media (max-width: 900px) {
  .ds-topbar { padding: 18px 20px; flex-wrap: wrap; }
  .ds-topbar__nav { gap: 16px; margin-top: 12px; margin-left: 0; width: 100%; overflow-x: auto; }
}
