/* Brand colours match the app's light palette. The marketing website uses
   a brighter page background, approved during the site-wide layout review.
   App theme tokens are unchanged.
   --link is the app's TOKENS.positive - same value in both themes there,
   so it's the same here.

   Deliberately no dark variant / prefers-color-scheme block: the app
   follows the device or an in-app choice, but this site always renders
   the one light theme regardless of the visitor's OS setting - proof of
   dark mode support lives in the "light or dark" screenshots (index.html)
   instead of the site actually switching. */
:root {
  --bg: #fafbfe;
  --surface: #ffffff;
  --ink: #1b2456;
  --ink-muted: #5f6a93;
  --accent: #e0672b;
  --link: #5b8fc7;
  --hairline: #dde2ee;
  --glass: rgba(255, 255, 255, 0.6);
  --card-shadow: 0 1px 2px rgba(27, 36, 86, 0.08);
}

* {
  box-sizing: border-box;
}

/* The native `hidden` attribute's built-in `display: none` has the same
   low specificity as a plain class selector, so any component class that
   sets its own `display` (e.g. .roi-result-row's `display: flex`) quietly
   wins and the element stays visible - a real bug this caught on
   solar-battery-calculator.html's payback row. Toggle visibility with
   `el.hidden` everywhere on this site (not `style.display`), and this
   makes that actually work regardless of what a component's own class
   sets `display` to. */
[hidden] {
  display: none !important;
}

html {
  color-scheme: light;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: 'IBM Plex Sans', sans-serif;
}

.sky-band canvas {
  filter: brightness(1.12) saturate(1.08);
}

a {
  color: var(--link);
  text-decoration: none;
}

a:hover {
  filter: brightness(0.9);
}

.eyebrow {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0;
}

/* Dark ink, not orange - the app's own primary button (AuthScreen.jsx's
   real Sign in submit) is TOKENS.ink, not TOKENS.sun. Orange there is
   reserved for Plus/upgrade signalling specifically (see .card--plus /
   .tier-label--plus below, which do mirror that), not general actions -
   a plain "Sign in" CTA using it had no basis in how the app itself
   actually uses these two colours. */
.cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--ink);
  color: #ffffff;
  border: none;
  border-radius: 10px;
  padding: 13px 26px;
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 14.5px;
  cursor: pointer;
  white-space: nowrap;
}

.cta--small {
  border-radius: 8px;
  padding: 8px 13px;
  font-size: 12.5px;
}

.cta--ghost {
  background: none;
  color: var(--ink);
  border: 1px solid var(--hairline);
}

.app-entry-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 16px;
}

.app-entry-actions--context {
  --play-badge-height: 64px;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 12px;
  margin-top: 6px;
}

.bottom-cta .app-entry-actions--context {
  justify-content: center;
}

.web-app-entry {
  display: inline-grid;
  grid-template-rows: var(--play-badge-height) auto;
  justify-items: center;
}

.web-app-entry .cta {
  align-self: center;
}

.web-app-entry small {
  color: var(--ink-muted);
  font-size: 11px;
  line-height: 1.2;
}

.app-entry-actions--context .play-store-badge img {
  height: var(--play-badge-height);
}

.app-entry-signin {
  display: block;
  margin-top: 12px;
}

@media (max-width: 420px) {
  .app-entry-actions--context {
    --play-badge-height: 54px;
    gap: 8px;
  }

  .web-app-entry .cta {
    padding: 11px 14px;
    font-size: 13px;
  }
}

.play-store-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
}

.play-store-badge img {
  display: block;
  width: auto;
  height: 64px;
}

.play-store-badge:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 3px;
}

/* ---- nav -----------------------------------------------------------
   Fixed above everything else (z-index 3 - higher than .page-backdrop
   and the scrolling content) so it's a persistent bar, same as the app's
   own tab bar sitting over the sky: content passes BEHIND it and fades
   into the frosted glass, it never passes in front and covers the nav.
   Same frosted-glass treatment as the app's own overlay controls
   (App.jsx's Setup/Profile buttons) - legible over any sky colour. */
.site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 3;
}

.nav {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  max-width: 1100px;
  margin: 0 auto;
  padding: 20px 24px;
}

.wordmark,
.wordmark-small {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: 'Fraunces', serif;
  font-weight: 600;
  color: var(--ink);
}

.wordmark {
  font-size: 19px;
}

.wordmark-small {
  font-size: 14px;
  color: var(--ink-muted);
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 12px;
}

.nav-link {
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink);
  padding: 6px 2px;
  border-bottom: 1.5px solid transparent;
  white-space: nowrap;
}

.nav-link:hover {
  filter: none;
  border-bottom-color: var(--hairline);
}

.nav-link[aria-current='page'] {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

/* frosted panel wrapping the nav - legible over the sky, and once content
   has scrolled up underneath it, the blur + tint is what makes it read as
   "fading behind" rather than a hard cut. */
.nav-glass {
  position: relative;
  z-index: 2;
  background: var(--glass);
  backdrop-filter: blur(9px) saturate(1.15);
  -webkit-backdrop-filter: blur(9px) saturate(1.15);
  border-bottom: 1px solid var(--hairline);
}

.nav-toggle {
  display: none;
  background: var(--glass);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  width: 38px;
  height: 38px;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  color: var(--ink);
}

@media (max-width: 720px) {
  .nav-toggle {
    display: flex;
  }
  .nav-links {
    position: absolute;
    top: calc(100% + 8px);
    right: 24px;
    left: 24px;
    flex-direction: column;
    align-items: stretch;
    gap: 2px;
    background: var(--surface);
    border: 1px solid var(--hairline);
    border-radius: 14px;
    padding: 10px;
    box-shadow: 0 12px 30px rgba(27, 36, 86, 0.18);
  }
  .nav-links[data-open='false'] {
    display: none;
  }
  .nav-link {
    padding: 10px 8px;
    border-bottom: none;
    border-radius: 8px;
  }
  .nav-link:hover {
    background: var(--bg);
  }
  .nav-links .cta {
    margin-top: 4px;
  }
}

/* ---- sky band --------------------------------------------------------
   Same renderer as the app's SkyHeader (see sky.js), pinned to one fixed
   scene (partly cloudy, London, 15:00) rather than the app's live
   clock/weather - a marketing page shouldn't depend on a weather API call
   or look different depending on when someone visits. Nav sits on top of
   it; page content dissolves in underneath, same as the app.

   Fixed to the viewport, same "background stays put, content moves in
   front" effect as the app (App.jsx's Estimate/Performance view - see
   its comment on the same technique). Unlike the app - which bounds this
   to one phone-sized box with its own inner scroll layer - this is a real
   full-height page, so the simpler equivalent is: pin the sky/nav to the
   viewport and let normal page scroll carry the (opaque) content up over
   it. A .sky-spacer right after each .sky-band reserves the matching
   height in normal flow, so content starts exactly where the sky ends. */
.sky-band {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 0;
  isolation: isolate;
  overflow: hidden;
}

.sky-spacer--hero {
  height: 260px;
}

.sky-spacer--compact {
  height: 150px;
}

/* The actual dissolve-to-solid-page happens here, NOT on `main` - main and
   the footer carry no background of their own and sit transparently over
   this. Giving the content block its own opaque background instead (an
   earlier attempt) reads as a second, separate sheet sliding over the
   sky rather than one continuous surface - the app never has that seam,
   because its "surface fades in" layer (SkyHeader.jsx's surfaceLayerRef)
   is part of the fixed backdrop too, not something that scrolls with the
   content. Fixed + masked the same way: transparent where the sky shows,
   solid var(--bg) by the time content starts, and solid forever below
   that regardless of scroll position. */
.page-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1;
  background: var(--bg);
  pointer-events: none;
}

.page-backdrop--hero,
.page-backdrop--compact {
  -webkit-mask-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0,
    rgba(0, 0, 0, 0) 50px,
    rgba(0, 0, 0, 0.55) 150px,
    rgba(0, 0, 0, 0.88) 210px,
    #000 260px,
    #000 100%
  );
  mask-image: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 0,
    rgba(0, 0, 0, 0) 50px,
    rgba(0, 0, 0, 0.55) 150px,
    rgba(0, 0, 0, 0.88) 210px,
    #000 260px,
    #000 100%
  );
}

main,
.site-footer {
  position: relative;
  z-index: 2;
}

.sky-band canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  /* dissolves into the page background, same shape as the app's own
     canvas mask (SkyHeader.jsx) - a hard-edged sky photo would look
     pasted on, not "part of the app". */
  -webkit-mask-image: linear-gradient(
    to bottom,
    #000 0%,
    #000 22%,
    rgba(0, 0, 0, 0.85) 46%,
    rgba(0, 0, 0, 0.45) 70%,
    rgba(0, 0, 0, 0) 100%
  );
  mask-image: linear-gradient(
    to bottom,
    #000 0%,
    #000 22%,
    rgba(0, 0, 0, 0.85) 46%,
    rgba(0, 0, 0, 0.45) 70%,
    rgba(0, 0, 0, 0) 100%
  );
}

.sky-band--hero {
  height: 260px;
}

.sky-band--compact {
  height: 260px;
}

.sky-caption {
  max-width: 1100px;
  margin: 0 auto;
  padding: 4px 24px 0;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 12px;
  color: var(--ink-muted);
}

.trial-note {
  margin: 10px 0 0;
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--accent);
}

/* Every visible "£1.76/month" mention (compare table, FAQ, about, the
   GivEnergy page) gets this treatment: the price struck through in the
   same orange as .trial-note above, plus a small pill calling out the
   free trial, so the free-trial promo is impossible to miss wherever the
   price appears - not just on the homepage hero/bottom-cta. Both pieces
   share one inline-flex wrapper so they wrap together as a unit on
   narrow widths instead of splitting mid-phrase. */
.price-trial {
  display: inline-flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px 8px;
}

.price-was {
  color: var(--accent);
  text-decoration: line-through;
  text-decoration-thickness: 1.5px;
  text-decoration-color: var(--accent);
  opacity: 0.68;
}

.price-trial-badge {
  display: inline-block;
  background: rgba(224, 103, 43, 0.14);
  color: var(--accent);
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 700;
  font-size: 0.82em;
  letter-spacing: 0.02em;
  line-height: 1.5;
  padding: 1px 9px;
  border-radius: 999px;
  white-space: nowrap;
}

.hero,
.energy-feature,
.why,
.diagram,
.showcase,
.ev-feature,
.compatibility,
.tiers,
.bottom-cta {
  max-width: 760px;
  margin: 0 auto;
  padding: 8px 24px 72px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
}

/* Lets .chart-cards below query this element's own content-box to tell
   "genuinely fits side by side" from "needs to scroll". */
.showcase {
  container-type: inline-size;
}

.hero {
  max-width: 100%;
  padding: 28px 24px 76px;
  gap: 18px;
}

.hero .hero-identity {
  max-width: 760px;
  margin: 8px 0 4px;
}
.hero-identity__brand {
  position: relative;
  isolation: isolate;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 14px;
  font-size: clamp(52px, 8vw, 88px);
  line-height: 1.2;
  padding: 28px 0;
}
.hero-identity__emblem {
  position: relative;
  display: flex;
  flex-shrink: 0;
}
.hero-identity__atlas {
  display: none;
  position: absolute;
  left: 50%;
  top: 0;
  width: min(100%, 500px);
  height: auto;
  transform: translateX(-50%);
  z-index: -1;
  pointer-events: none;
}
.hero-identity__continents {
  fill: #b8d5ec;
  stroke: #8cb5d7;
  stroke-width: 0.8;
  opacity: 0.65;
}
.hero-identity__night {
  fill: #1b2456;
  opacity: 0.55;
}
.hero--map .hero-identity__atlas {
  display: block;
}
.hero--map .hero-identity__brand {
  padding-top: clamp(145px, 30vw, 215px);
}
.weather-state {
  opacity: 0;
  animation: hero-weather-cycle 20s linear infinite;
}
.weather-state--cloud {
  animation-delay: 5s;
}
.weather-state--rain {
  animation-delay: 10s;
}
.weather-state--snow {
  animation-delay: 15s;
}
.weather-rain {
  animation: hero-rain-fall 1s linear infinite;
}
.weather-snow {
  animation: hero-snow-fall 2s ease-in-out infinite alternate;
}
.hero--map .weather-state {
  animation: none;
  opacity: 0;
}
.hero--map .weather-state--sun {
  opacity: 1;
}
.hero-identity__symbol {
  width: clamp(65px, 9vw, 106px);
  height: auto;
  flex-shrink: 0;
}
.hero-identity__rays {
  transform-origin: 50px 50px;
}
.hero-identity__description {
  display: block;
  margin-top: 20px;
  font:
    500 clamp(18px, 2.3vw, 24px)/1.45 'Inter',
    sans-serif;
  color: var(--ink-muted);
}
@keyframes hero-weather-cycle {
  0%,
  20% {
    opacity: 1;
  }
  25%,
  95% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
@keyframes hero-rain-fall {
  from {
    transform: translateY(-3px);
    opacity: 0.4;
  }
  to {
    transform: translateY(4px);
    opacity: 1;
  }
}
@keyframes hero-snow-fall {
  from {
    transform: translate(-2px, -2px);
  }
  to {
    transform: translate(2px, 3px);
  }
}
@media (prefers-reduced-motion: reduce) {
  .weather-state,
  .weather-rain,
  .weather-snow {
    animation: none;
  }
  .weather-state--sun {
    opacity: 1;
  }
}

h1 {
  font-family: 'Fraunces', serif;
  font-weight: 600;
  font-size: 46px;
  line-height: 1.12;
  color: var(--ink);
  margin: 0;
  max-width: 700px;
}

h2 {
  font-family: 'Fraunces', serif;
  font-weight: 600;
  font-size: 27px;
  line-height: 1.3;
  color: var(--ink);
  margin: 0;
}

.lede {
  font-size: 16.5px;
  line-height: 1.6;
  color: var(--ink-muted);
  max-width: 540px;
  margin: 0;
}

.hero-benefits {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  max-width: 720px;
  margin: 2px 0 0;
  padding: 0;
  list-style: none;
}

.hero-benefits li {
  padding: 10px 12px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  background: color-mix(in srgb, var(--surface) 84%, transparent);
  color: var(--ink-muted);
  font-size: 13px;
  line-height: 1.42;
}

.why p:not(.eyebrow) {
  font-size: 15px;
  line-height: 1.65;
  color: var(--ink-muted);
  max-width: 560px;
  margin: 0;
}

@media (max-width: 560px) {
  .hero-benefits {
    grid-template-columns: 1fr;
    width: min(100%, 340px);
  }
}

/* ---- how it works (system diagram) ------------------------------------ */
.diagram {
  max-width: 980px;
}

.diagram-frame {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

.diagram-frame img {
  display: block;
  width: 100%;
  height: auto;
  margin: 8px 0 0;
}

/* Mirrors .cta--ghost's look (bordered, no fill) rather than inventing a
   new button style - this is a secondary, non-CTA action, not another
   call to action. Sits below the diagram rather than floating on top of
   it - the diagram is wide and short, so an overlaid corner button ends
   up sitting on top of a box's text at most widths. */
.diagram-expand {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 7px 12px;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}

.diagram-expand:hover {
  background: var(--surface);
}

/* ---- diagram modal -----------------------------------------------------
   Plain click-to-zoom/drag-to-pan, no library - the diagram's viewBox
   text is a fixed size relative to the image, so on a narrow phone the
   whole thing (labels included) shrinks with it. Letting people blow it
   up and pan around solves that directly instead of just nudging the
   base font-size and hoping it's enough at every width. */
.diagram-modal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 20;
  align-items: center;
  justify-content: center;
}

.diagram-modal[aria-hidden='false'] {
  display: flex;
}

.diagram-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 20, 40, 0.55);
}

.diagram-modal-panel {
  position: relative;
  z-index: 1;
  width: min(96vw, 1200px);
  height: min(90vh, 800px);
  background: var(--surface);
  border-radius: 16px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 60px rgba(15, 20, 40, 0.35);
}

.diagram-modal-toolbar {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--hairline);
  flex: 0 0 auto;
}

.diagram-modal-toolbar button {
  background: var(--bg);
  border: 1px solid var(--hairline);
  color: var(--ink);
  border-radius: 8px;
  width: 34px;
  height: 34px;
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.diagram-modal-toolbar button[data-diagram-zoom-reset] {
  width: auto;
  padding: 0 12px;
  font-size: 12.5px;
  font-family: 'IBM Plex Mono', monospace;
  letter-spacing: 0.04em;
}

.diagram-modal-toolbar button:hover {
  background: var(--surface);
  border-color: var(--ink-muted);
}

.diagram-modal-close {
  margin-left: 4px;
}

.diagram-modal-viewport {
  position: relative;
  flex: 1 1 auto;
  overflow: hidden;
  touch-action: none;
  cursor: grab;
  background:
    linear-gradient(90deg, var(--hairline) 1px, transparent 1px) 0 0 / 32px 32px,
    linear-gradient(var(--hairline) 1px, transparent 1px) 0 0 / 32px 32px,
    var(--bg);
}

.diagram-modal-viewport.dragging {
  cursor: grabbing;
}

.diagram-modal-viewport img {
  position: absolute;
  left: 0;
  top: 0;
  width: 900px;
  max-width: none;
  transform-origin: 0 0;
  user-select: none;
  -webkit-user-drag: none;
}

.diagram-modal-hint {
  margin: 0;
  padding: 8px 12px;
  font-size: 11.5px;
  text-align: center;
  color: var(--ink-muted);
  border-top: 1px solid var(--hairline);
  flex: 0 0 auto;
}

@media (max-width: 640px) {
  .diagram-modal-panel {
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    border-radius: 0;
  }
}

/* ---- showcase (real chart exports, not mockups) ----------------------- */
.showcase {
  max-width: 1360px;
}

.showcase-eyebrow {
  margin-bottom: 4px;
}

/* Always nowrap + overflow-x, at every width, no breakpoint - this is what
   actually guarantees "either all four fit in one row, or it's a genuine
   carousel", never the in-between: flex-wrap:wrap used to let a laptop-
   width viewport fit 3 cards and drop the 4th onto its own line, which is
   worse than either real outcome. Whether it's a static row or a carousel
   now falls entirely out of whether four 300px cards + gaps actually fit
   this container - .showcase's max-width is sized so a wide desktop
   genuinely can (see initCarousel() in main.js: it already no-ops
   wherever scrollWidth doesn't exceed clientWidth). */
/* Side padding matches half the card's own max-width, so the FIRST and
   LAST card have somewhere to scroll to - without it, a card sitting at
   the very edge of the scrollable area physically cannot reach centre
   (there's no scroll range left to bring it there), so it's stuck angled
   with no way to look at it straight on. max() keeps this sane if the
   viewport is narrower than the card itself. */
.home-flow {
  width: 100%;
  max-width: 680px;
  margin: 38px auto 0;
  padding: 20px 12px 16px;
  border-radius: 24px;
  background: linear-gradient(140deg, #fff7ee, #ffffff 48%, #eef6ff);
  box-shadow: 0 12px 40px rgba(27, 36, 86, 0.06);
}
.home-flow svg {
  display: block;
  width: 100%;
  overflow: visible;
}
.home-flow__routes {
  stroke: #d9e1ef;
  stroke-width: 3;
}
.home-flow__streams {
  stroke: #ff6825;
  stroke-width: 5;
  stroke-linecap: round;
  stroke-dasharray: 1 21;
}
.home-flow__streams path {
  animation: home-energy-travel 1.8s linear infinite;
  animation-play-state: paused;
}
.home-flow__home {
  stroke: #5498e0;
}
.home-flow__battery {
  animation-delay: -0.6s !important;
}
.home-flow__car {
  animation-delay: -1.2s !important;
  stroke: #5498e0;
}
.home-flow.is-running:not(.is-page-hidden) .home-flow__streams path {
  animation-play-state: running;
}
.home-flow__nodes {
  fill: #fff;
  stroke: #e0e6f0;
  stroke-width: 1.5;
}
.home-flow__labels {
  fill: #1b2456;
  font:
    600 20px system-ui,
    sans-serif;
}
.home-flow__labels text[x='300'] {
  font-size: 14px;
}
.home-flow__symbol {
  fill: #ff6825;
  font-size: 30px;
}
.home-flow figcaption {
  color: var(--ink-muted);
  font-size: 12px;
  text-align: center;
  margin-top: 8px;
}
.home-reveal {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity 450ms ease,
    transform 450ms ease;
}
.home-reveal.is-revealed {
  opacity: 1;
  transform: none;
}
.carousel-controls {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin: 4px 0 24px;
}
.carousel-controls[hidden] {
  display: none;
}
.carousel-controls button {
  min-height: 44px;
  padding: 10px 18px;
  border: 1px solid #d9e1ef;
  border-radius: 24px;
  background: #fff;
  color: #1b2456;
  font:
    600 14px system-ui,
    sans-serif;
  cursor: pointer;
}
.carousel-controls button:hover:not(:disabled) {
  border-color: #5498e0;
  background: #eef6ff;
}
.carousel-controls button:disabled {
  opacity: 0.4;
  cursor: default;
}
.carousel-controls button:focus-visible {
  outline: 2px solid #5498e0;
  outline-offset: 3px;
}
@keyframes home-energy-travel {
  to {
    stroke-dashoffset: -44;
  }
}
@media (prefers-reduced-motion: reduce) {
  .home-flow__streams path {
    animation: none;
  }
  .home-reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

.chart-cards {
  display: flex;
  gap: 20px;
  flex-wrap: nowrap;
  justify-content: flex-start;
  width: 100%;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding: 10px max(20px, calc(50% - 160px)) 28px;
  scrollbar-width: none;
  -ms-overflow-style: none;
}

/* The buffer above always reserves half a card's width per side, which
   caps the visible strip at one card wide even once the container is
   roomy enough that all four could sit unscrolled - that's fine here
   (.showcase's 760px max-width never gets that roomy), but kept as an
   @container escape hatch if .showcase's max-width ever grows. */
@container (min-width: 1340px) {
  .chart-cards {
    padding: 10px 20px 28px;
  }
}

.chart-cards::-webkit-scrollbar {
  display: none;
}

/* No border - a hairline outline plus a shadow is the same "boxed
   component" recipe repeated everywhere, which is exactly what read as
   templated. A softer two-layer shadow (a tight contact shadow plus a
   longer ambient one) does the job of separating the card from the page
   without drawing a hard line around it. */
.chart-card {
  flex: 1 0 300px;
  max-width: 320px;
  scroll-snap-align: center;
  transform-origin: center center;
  text-align: left;
  background: var(--surface);
  border-radius: 16px;
  box-shadow:
    0 1px 3px rgba(27, 36, 86, 0.06),
    0 14px 32px rgba(27, 36, 86, 0.07);
  padding: 18px 18px 20px;
}

.chart-card img {
  display: block;
  width: 100%;
  height: auto;
  margin: 6px 0 12px;
}

/* The app's own section-header style (ActualScreen.jsx's sectionLabel /
   EstimateScreen.jsx's "Today's estimate" label), not this site's own
   Free/Plus tier badge - these four cards are meant to look lifted
   straight from the app, not marked up with this site's own labelling. */
.card-header {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 8px;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* Matches charts.jsx's own line-legend exactly: a small halo+ink line
   swatch (the same two-stroke style as the chart's actual solar-line)
   paired with the caption, not just the caption text on its own - the
   swatch is the only thing that actually tells you what the line looks
   like. */
.chart-note {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 0 10px;
  font-size: 11.5px;
  color: var(--ink-muted);
}

.chart-note svg {
  flex: none;
}

.chart-card p {
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-muted);
  margin: 0;
}

.chart-card p strong {
  color: var(--ink);
}

/* ---- bill estimator card (real numbers, real structure - straight from
   ActualScreen.jsx's CostBreakdown: label and rate on one line joined by
   " · ", with an indented "up-and-right" sub-row under each import band
   for how much of it went to the house vs the car. Any band that doesn't
   split just doesn't get sub-rows (Exported/Standing charge never do). */
.bill-rows {
  margin: 6px 0 12px;
  border-top: 1px solid var(--hairline);
}

.bill-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--hairline);
  font-size: 12px;
  color: var(--ink);
}

.bill-sub {
  color: var(--ink-muted);
  font-size: 11px;
}

.bill-row b {
  flex: none;
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
}

.bill-row b.bill-negative {
  color: var(--link);
}

.bill-row--sub {
  padding: 1px 0 1px 14px;
  border-bottom: none;
  font-size: 11px;
  color: var(--ink-muted);
}

.bill-row--total {
  border-bottom: none;
  padding-top: 10px;
}

.bill-row--total span,
.bill-row--total b {
  font-weight: 700;
  color: var(--ink);
  font-size: 13px;
}

/* ---- energy-flow card legend - matches charts.jsx's FlowLegend exactly:
   the three "Solar" rows sit inside their own bordered group, the other
   three (battery/grid/car) sit beside it unboxed, and each row is a
   swatch plus a two-line (label, then kWh) stack, not a single inline
   row. Colours are lifted straight from chart-energy-flow.svg, so the
   swatches actually match the bands in the image above them. */
.energy-legend {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  align-items: flex-start;
  margin-top: 8px;
}

/* A tint, not an outline - a box inside the card that's already a box
   is exactly the nesting that reads as componentised rather than
   designed. */
.energy-legend-solar {
  background: var(--bg);
  border-radius: 10px;
  padding: 6px 10px 7px;
}

.energy-legend-heading {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 9px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 5px;
}

.energy-legend-rows,
.energy-legend-other {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
}

.energy-legend-other {
  padding-top: 6px;
}

.energy-legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
}

.energy-swatch {
  width: 11px;
  height: 11px;
  border-radius: 2px;
  flex: none;
  border: 1px solid rgba(0, 0, 0, 0.18);
}

.energy-item-label {
  display: block;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 11px;
  color: var(--ink-muted);
}

.energy-item-value {
  display: block;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
}

/* Real wording lifted verbatim from ActualScreen.jsx's per-car-charging
   sentence, in the same place it sits in the app: a small violet swatch
   (the same "car" colour as the chart band) and a border-top rule
   separating it from the legend above - not a boxed-out callout, which
   was never how the app itself presents this line. The feature it's
   demonstrating (grid-side vs behind-the-battery charger wiring) gets
   its own section further down the page instead of a note crammed in
   here - see .ev-feature. */
.ev-line {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--hairline);
}

.ev-line .energy-swatch {
  width: 9px;
  height: 9px;
  margin-top: 4px;
  border: none;
  background: rgb(108, 75, 209);
}

.ev-line p {
  margin: 0;
  font-size: 11px;
  line-height: 1.5;
  color: var(--ink-muted);
}

.ev-line p b {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 600;
  color: var(--ink);
}

/* ---- self-sufficiency card - its own card in the app (formPrimitives.jsx's
   SelfSufficiencyStat), not nested inside the energy-used card. */
.self-suff {
  display: flex;
  align-items: center;
  gap: 14px;
}

.self-suff-label {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--ink);
}

.self-suff-note {
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 11.5px;
  color: var(--ink-muted);
  margin-top: 2px;
  line-height: 1.4;
  max-width: 190px;
}

/* ---- compatibility -------------------------------------------------- */
.compatibility-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  width: 100%;
  gap: 10px;
  text-align: left;
}

.compatibility-grid > div {
  min-height: 112px;
  padding: 14px;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: var(--surface);
}

.compatibility-grid p {
  margin: 0;
  color: var(--ink-muted);
  font-size: 13px;
  line-height: 1.45;
}

.compatibility-grid .compatibility-label {
  margin-bottom: 7px;
  color: var(--ink);
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* Phone-only refinement: a 300px-fixed card leaves almost no peek of the
   next one on a ~375px screen. Doesn't touch nowrap/overflow (those are
   universal now, see .chart-cards above) - just widens the card at a
   width where 300px fixed would otherwise look edge-to-edge. */
@media (max-width: 480px) {
  .chart-card {
    flex-basis: 82%;
    max-width: 82%;
  }

  .compatibility-grid {
    grid-template-columns: 1fr;
  }

  .compatibility-grid > div {
    min-height: 0;
  }
}

/* ---- energy-flow feature - "How your energy was used" pulled out of the
   showcase carousel into its own early section, right after the hero and
   before "why this exists": a bigger differentiator than one card among
   several deserves, and no longer competing with autoplay for attention.
   Same chart-card visual language (border/shadow/padding), just standalone
   and wider - the chart reads better with more room, and it's vector so
   scaling it up costs nothing. */
.energy-feature-card {
  width: 100%;
  max-width: 520px;
  text-align: left;
  background: var(--surface);
  border-radius: 16px;
  box-shadow:
    0 1px 3px rgba(27, 36, 86, 0.06),
    0 14px 32px rgba(27, 36, 86, 0.07);
  padding: 20px 22px 24px;
}

.energy-feature-card img {
  display: block;
  width: 100%;
  height: auto;
  margin: 8px 0 14px;
}

/* ---- EV charger topology - its own section, not a note buried in the
   showcase carousel. The two option titles/descriptions are lifted
   verbatim from SetupPage.jsx's own charger_topology radio choices, since
   that's the actual real answer a user picks - not a paraphrase of it. */
.ev-feature {
  max-width: 680px;
}

/* Two identical bordered cards side by side was the same "pair of
   boxes" tell as the old Free/Plus comparison - this uses the same fix:
   one connected block split by a single rule, not two floating panels.
   The rule runs down the middle at rest and rotates to a horizontal
   divider once the pair stacks, so there's always exactly one seam,
   never a leftover empty edge from a card that no longer has a partner
   beside it. */
.ev-topology {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  width: 100%;
  text-align: left;
}

.ev-topology-option {
  flex: 1 1 260px;
  padding: 0 28px;
}

.ev-topology-option:first-child {
  border-right: 1px solid var(--hairline);
}

@media (max-width: 580px) {
  .ev-topology-option {
    padding: 24px 0 0;
  }
  .ev-topology-option:first-child {
    border-right: none;
    border-bottom: 1px solid var(--hairline);
    padding: 0 0 24px;
  }
}

.ev-topology-title {
  margin: 0 0 6px;
  font-weight: 600;
  color: var(--ink);
  font-size: 14px;
}

.ev-topology-option img {
  display: block;
  width: 100%;
  height: auto;
  margin: 4px 0 10px;
}

.ev-topology-option p:not(.ev-topology-title) {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-muted);
}

.tiers {
  max-width: 620px;
}

.tiers-eyebrow {
  margin-bottom: 4px;
}

/* A plain pivot-style outline, not a pair of cards or a side-by-side grid -
   each tier is a row heading; what it includes are the plain rows nested
   under it. Reads top to bottom like a real list, not a grid to scan, and
   needs no horizontal scroll at any width since there's only one column. */
.compare-table {
  width: 100%;
  max-width: 480px;
  border-collapse: collapse;
  text-align: left;
  margin-bottom: 24px;
}

.compare-tier-row th {
  padding: 16px 0 8px;
  border-bottom: 1px solid var(--hairline);
  font-family: 'Fraunces', serif;
  font-weight: 600;
  font-size: 18px;
  color: var(--ink);
}

.compare-table tbody tr:first-child th {
  padding-top: 0;
}

.compare-tier-row--plus th {
  color: var(--accent);
}

.compare-price {
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 400;
  font-size: 12.5px;
  color: var(--ink-muted);
  margin-left: 4px;
}

.compare-feature-row td {
  padding: 9px 0 9px 16px;
  border-bottom: 1px solid var(--hairline);
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 13.5px;
  color: var(--ink-muted);
}

.tier-label {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 4px;
}

.tier-label--plus {
  color: var(--accent);
  font-weight: 600;
}

.bottom-cta {
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
  padding-top: 56px;
  padding-bottom: 56px;
}

/* One full-weight primary action, one quiet text link for the secondary
   path - the segmented tab-bar pill this replaced gave "Create account"
   and "Sign in" equal visual weight, which undersold the actual primary
   action. Matches the weighting AuthScreen.jsx itself already uses for
   this exact choice (its mode-toggle link, not a second button). */
.secondary-link {
  display: inline-block;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 13px;
  color: var(--ink-muted);
}

.secondary-link:hover {
  color: var(--ink);
  filter: none;
}

.site-footer {
  max-width: 1100px;
  margin: 0 auto;
  padding: 24px 24px 40px;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 16px 24px;
}

.footer-links {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px 18px;
  flex-wrap: wrap;
}

.footer-links a {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 6px 0;
  color: var(--ink-muted);
  font-size: 12.5px;
}

.footer-links a:hover {
  color: var(--ink);
}

.disclaimer {
  grid-column: 1 / -1;
  font-size: 12px;
  line-height: 1.6;
  color: var(--ink-muted);
}

@media (max-width: 720px) {
  .site-footer {
    grid-template-columns: minmax(0, 1fr);
  }

  .footer-links {
    justify-content: flex-start;
  }
}

/* ---- simple content pages (Terms, Privacy, Contact, 404) ------------- */
.page {
  max-width: 720px;
  margin: 0 auto;
  padding: 40px 24px 32px;
}

.page-header {
  margin-bottom: 32px;
}

.page-header h1 {
  font-size: 34px;
  max-width: none;
  margin-top: 8px;
}

.request-integration {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 12px;
  width: 100%;
  margin-top: 10px;
  scroll-margin-top: 120px;
}

.page .request-integration h2 {
  margin-top: 0;
}

.page .request-integration p {
  margin-bottom: 0;
}

.page .request-integration__details > p:first-child {
  margin-top: 0;
  font-weight: 600;
  color: var(--ink);
}

.page .request-integration__details ul {
  margin: 0 0 18px;
}

.request-integration__details > a {
  display: inline-block;
  font-weight: 600;
}

.page .request-integration__safety {
  margin: 12px 0 0;
  font-size: 12.5px;
}

@media (max-width: 620px) {
  .request-integration {
    grid-template-columns: minmax(0, 1fr);
    gap: 16px;
  }

  .request-integration__details {
    padding: 0;
    border: 0;
  }
}

.page--ev {
  max-width: 980px;
}

.ev-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 440px);
  align-items: center;
  gap: 48px;
  margin-bottom: 56px;
}

.ev-hero .page-header {
  margin: 0;
}

.ev-hero h1 {
  font-size: clamp(32px, 4vw, 48px);
  line-height: 1.15;
}

.ev-hero-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 20px;
  margin-top: 24px;
}

.ev-hero-actions .secondary-link {
  margin: 0;
}

.ev-hero-visual {
  margin: 0;
}

.ev-hero-photo {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--hairline);
  border-radius: 18px;
  box-shadow: 0 14px 34px rgba(27, 36, 86, 0.1);
}

.ev-hero-photo > img {
  display: block;
  width: 100%;
  height: auto;
}

.ev-photo-watermark {
  position: absolute;
  right: 14px;
  bottom: 14px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 10px 6px 6px;
  border-radius: 9px;
  background: rgba(244, 246, 251, 0.9);
  color: var(--ink);
  font-family: 'Fraunces', serif;
  font-size: 15px;
  font-weight: 600;
  line-height: 1;
  backdrop-filter: blur(5px);
}

.ev-photo-watermark img {
  width: 26px;
  height: 26px;
}

.page--ev > .ev-proof {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(240px, 320px);
  align-items: center;
  gap: 42px;
  max-width: 880px;
  padding-top: 40px;
  border-top: 1px solid var(--hairline);
}

.ev-proof figure {
  margin: 0;
}

.ev-proof figure img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  box-shadow: 0 10px 26px rgba(27, 36, 86, 0.08);
}

.ev-proof figcaption {
  margin-top: 9px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-muted);
}

.page--ev > section {
  max-width: 720px;
  margin-left: auto;
  margin-right: auto;
}

@media (max-width: 740px) {
  .ev-hero {
    grid-template-columns: minmax(0, 1fr);
    gap: 28px;
    margin-bottom: 40px;
  }

  .ev-hero-visual {
    max-width: 440px;
    margin: 0 auto;
  }

  .page--ev > .ev-proof {
    grid-template-columns: minmax(0, 1fr);
    gap: 26px;
  }

  .ev-proof figure {
    max-width: 340px;
    margin: 0 auto;
  }
}

.page-updated {
  font-size: 12.5px;
  color: var(--ink-muted);
  margin-top: 8px;
}

.legal-notice {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 14px 16px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-muted);
  margin-bottom: 36px;
}

.legal-notice strong {
  color: var(--ink);
}

/* Head-to-head comparison table (givenergy-monitoring-alternative.html) -
   a real two-column table since there are genuinely two things being
   compared side by side, unlike .compare-table's single-column pivot
   above (which lists what ONE product includes, not two side by side).
   The Wattlas column gets a light accent tint, not colored text, so
   longer sentences stay readable. */
.vs-table {
  width: 100%;
  /* Auto layout (the default) sizes each column from its widest
     un-wrapped content across every row - fine for the first table this
     component shipped with (short cell text), but a longer phrase in a
     later table (blog/wattlas-vs-solaredge-monitoring.html's cells) blew
     the column-width sum past a 375px viewport and forced the whole page
     wider. Fixed layout sizes columns from the table's own width and
     .vs-table tbody th's 26% below instead, so cell content is what
     wraps, never what expands the table. */
  table-layout: fixed;
  border-collapse: collapse;
  margin: 18px 0 28px;
  font-size: 13.5px;
}

.vs-table th,
.vs-table td {
  padding: 10px 12px;
  border-bottom: 1px solid var(--hairline);
  text-align: left;
  vertical-align: top;
  line-height: 1.55;
  overflow-wrap: break-word;
}

.vs-table thead th {
  font-family: 'Fraunces', serif;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  border-bottom: 2px solid var(--hairline);
}

.vs-table tbody th {
  font-weight: 500;
  color: var(--ink);
  width: 26%;
}

.vs-table td {
  color: var(--ink-muted);
}

.vs-table-col--wattlas {
  background: rgba(224, 103, 43, 0.06);
}

.vs-table thead .vs-table-col--wattlas {
  color: var(--accent);
}

.page section + section {
  margin-top: 30px;
}

.page h2 {
  font-size: 18px;
  margin-bottom: 10px;
}

.page p,
.page li {
  font-size: 14.5px;
  line-height: 1.7;
  color: var(--ink-muted);
}

.page ul {
  margin: 0;
  padding-left: 20px;
}

.page li + li {
  margin-top: 6px;
}

.page strong {
  color: var(--ink);
}

/* ---- contact page ----------------------------------------------------- */
.contact-card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 16px;
  box-shadow: var(--card-shadow);
  padding: 26px 24px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: flex-start;
}

.contact-email-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  width: 100%;
}

.contact-email {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 15px;
  color: var(--ink);
  background: var(--bg);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 9px 12px;
  user-select: all;
}

.copy-btn {
  font: inherit;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  background: none;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 9px 12px;
  cursor: pointer;
}

.copy-btn:hover {
  border-color: var(--ink-muted);
}

.copy-btn[data-copied='true'] {
  color: var(--link);
  border-color: var(--link);
}

/* ---- FAQ page - plain <details>/<summary>, no JS needed for the
   accordion itself (main.js only handles the nav toggle and carousels
   elsewhere on the site). */
.faq-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.faq-item {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 4px 18px;
}

.faq-item summary {
  padding: 14px 0;
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 14.5px;
  color: var(--ink);
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary::after {
  content: '+';
  flex: none;
  font-family: 'IBM Plex Mono', monospace;
  font-size: 18px;
  font-weight: 400;
  color: var(--ink-muted);
  transition: transform 0.15s ease;
}

.faq-item[open] summary::after {
  content: '\2212';
}

.faq-item p {
  margin: 0 0 16px;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--ink-muted);
}

/* ---- 404 ---------------------------------------------------------- */
.not-found {
  text-align: center;
  padding: 72px 24px 96px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
}

.not-found .code {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  letter-spacing: 0.1em;
  color: var(--ink-muted);
}

/* ---- blog (website/blog/) ------------------------------------------
   Post cards use the same shadow-only "soft card" recipe as .chart-card/
   .energy-feature-card (surface bg, 16px radius, no hairline border) -
   not .contact-card's bordered version - matching the direction set by
   the earlier card-softening pass. */
.post-list {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 28px;
}

.post-card {
  display: block;
  background: var(--surface);
  border-radius: 16px;
  box-shadow:
    0 1px 3px rgba(27, 36, 86, 0.06),
    0 14px 32px rgba(27, 36, 86, 0.07);
  padding: 22px 24px;
}

.post-card-date {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 6px;
}

/* Same img treatment as .chart-card/.energy-feature-card above - display
   block, full width, no border-radius (the hand-drawn diagram-style SVGs
   these point at already have their own rounded boxes, so clipping the
   image itself would just be redundant). */
.post-card img {
  display: block;
  width: 100%;
  height: auto;
  margin: 0 0 14px;
}

/* Individual post pages - same illustration, shown larger and centered
   above the article body rather than card-cropped. */
.post-hero-img {
  display: block;
  width: 100%;
  max-width: 420px;
  height: auto;
  margin: 4px auto 28px;
}

.post-card h2 {
  margin: 0 0 8px;
  font-size: 20px;
}

.post-card h2 a {
  color: var(--ink);
}

.post-card h2 a:hover {
  color: var(--accent);
  filter: none;
}

.post-card p {
  margin: 0 0 12px;
  font-size: 14px;
  line-height: 1.65;
  color: var(--ink-muted);
}

.post-card .read-more {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 13px;
  color: var(--link);
}

/* Individual post pages (website/blog/<slug>.html) reuse .page for the
   article body - this just adds the byline/date line under the h1. */
.post-meta {
  font-size: 12.5px;
  color: var(--ink-muted);
  margin-top: 8px;
}

@media (max-width: 560px) {
  h1 {
    font-size: 32px;
  }

  h2 {
    font-size: 22px;
  }

  .hero {
    padding: 20px 20px 56px;
  }

  .page-header h1 {
    font-size: 27px;
  }
}

/* ---- integrations hub (website/integrations/index.html) --------------
   One card per supported inverter/battery/charger/tariff, grouped under
   a category label. Same soft-shadow card recipe as .chart-card/
   .post-card - no separate visual language invented for this page. */
.integration-group + .integration-group {
  margin-top: 34px;
}

.charging-example {
  margin: 28px 0;
  padding: 22px 0;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}
.charging-example figcaption {
  font-size: 12px;
  color: var(--ink-muted);
  margin-bottom: 18px;
}
.charging-example__flow {
  display: block;
  width: min(100%, 460px);
  height: auto;
  margin: 0 auto;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 15px;
  color: var(--ink);
}
.charging-example__total {
  font-size: 23px;
  font-weight: 600;
}
.charging-example > p {
  margin: 18px 0 0;
  color: var(--ink);
}

.integration-group-title {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0 0 14px;
}

.integration-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 14px;
}

.integration-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow-wrap: anywhere;
  gap: 10px;
  background: var(--surface);
  border-radius: 14px;
  box-shadow:
    0 1px 3px rgba(27, 36, 86, 0.06),
    0 14px 32px rgba(27, 36, 86, 0.07);
  padding: 18px 18px 20px;
  color: var(--ink);
}

.integration-card:hover {
  filter: none;
  box-shadow:
    0 1px 3px rgba(27, 36, 86, 0.08),
    0 18px 38px rgba(27, 36, 86, 0.11);
}

.integration-card-icon {
  width: 38px;
  height: 38px;
  border-radius: 10px;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  color: var(--ink);
}

/* Energy supplier cards show the supplier's own logo on a white tile
   (same treatment as the guides' .post-brand-logo), in place of an icon. */
.integration-card-logo {
  height: 38px;
  box-sizing: border-box;
  padding: 6px 10px;
  border-radius: 10px;
  background: #ffffff;
  box-shadow: var(--card-shadow);
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  flex: none;
}

.integration-card-logo img {
  display: block;
  height: 26px;
  width: auto;
}

.integration-card h3 {
  margin: 0;
  font-family: 'Fraunces', serif;
  font-weight: 600;
  font-size: 16px;
  color: var(--ink);
}

.integration-card p {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-muted);
  flex: 1;
}

.integration-card-cta {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--link);
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.integration-card--soon {
  opacity: 0.6;
}

.integration-card--soon .integration-card-cta {
  color: var(--ink-muted);
}

.integration-outcomes {
  margin-top: 52px;
}

.integration-outcomes h2 {
  max-width: 630px;
  font-size: clamp(24px, 3vw, 34px);
}

.integration-outcomes-intro {
  max-width: 630px;
  margin: 12px 0 24px;
  color: var(--ink-muted);
  line-height: 1.7;
}

.integration-card--plain {
  cursor: default;
}

.integration-card--plain:hover {
  transform: none;
  border-color: var(--line);
}

.tool-chart-title {
  margin: 0 0 14px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
}

.tool-bar-chart {
  display: flex;
  height: 190px;
  align-items: end;
  gap: 6px;
}

.tool-bar-chart--compact {
  height: 128px;
}

.tool-bar-chart-item {
  display: flex;
  flex: 1;
  height: 100%;
  min-width: 0;
  flex-direction: column;
  justify-content: end;
  align-items: center;
  gap: 5px;
}

.tool-bar-chart-bar {
  display: flex;
  flex-direction: column-reverse;
  width: 100%;
  min-height: 3px;
  border-radius: 3px 3px 1px 1px;
  background: var(--accent);
}

.tool-bar-chart-bar i {
  width: 100%;
}
/* The top piece of a stacked bar fills whatever the rounded percentages
   leave, so the bar's own orange background never shows through as a
   sliver at the top (battery-only page, 7 Oct 2026). */
.tool-bar-chart-bar > i:last-child {
  flex: 1 1 auto;
}
.tool-array-0 {
  background: var(--accent);
}
.tool-array-1 {
  background: var(--link);
}
.tool-array-2 {
  background: var(--ink-muted);
}
.tool-chart-key {
  display: flex;
  gap: 12px;
  margin: -4px 0 10px;
  font-size: 10px;
  color: var(--ink-muted);
}
.tool-chart-key span {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.tool-array-swatch {
  width: 8px;
  height: 8px;
  border-radius: 50%;
}

.tool-flow-export,
.tool-flow-own,
.tool-flow-grid {
  flex: none;
}

.tool-monthly-chart-label {
  margin: 4px 0 16px;
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-muted);
}

.tool-bar-chart-value,
.tool-bar-chart-label,
.tool-flow-chart small {
  font-size: 10px;
  color: var(--ink-muted);
}

.tool-flow-chart,
.tool-cost-chart {
  display: grid;
  gap: 16px;
}

.tool-flow-chart p,
.tool-cost-chart span {
  margin: 0 0 6px;
  font-size: 12px;
  font-weight: 600;
}

.tool-flow-bar,
.tool-cost-track {
  display: flex;
  height: 12px;
  overflow: hidden;
  margin-bottom: 5px;
  border-radius: 99px;
  background: var(--hairline);
}

.tool-flow-solar,
.tool-flow-own,
.tool-cost-ev {
  background: var(--accent);
}
.tool-flow-export {
  flex: 1;
  background: var(--link);
}

.tool-bar-chart-bar .tool-flow-export,
.tool-bar-chart-bar .tool-flow-own,
.tool-bar-chart-bar .tool-flow-grid {
  flex: none;
}
.tool-flow-grid,
.tool-cost-ice {
  background: var(--ink-muted);
}
/* Car charging on the battery-only calculator's home-use bars */
.tool-flow-car {
  background: var(--link);
}
.tool-bar-chart-bar .tool-flow-car {
  flex: none;
}

.tool-cost-chart > div {
  display: grid;
  grid-template-columns: 94px 1fr auto;
  align-items: center;
  gap: 10px;
}

.tool-cost-track {
  margin: 0;
}
.tool-cost-chart b {
  font-size: 12px;
}

.tool-line-chart-key {
  display: flex;
  gap: 14px;
  margin: -4px 0 8px;
  font-size: 10px;
  color: var(--ink-muted);
}

.tool-line-chart-key span {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.tool-line-chart-key i {
  width: 16px;
  height: 3px;
  border-radius: 99px;
}

.tool-line-chart-ev {
  background: var(--accent);
}

.tool-line-chart-ice {
  background: var(--ink-muted);
}

.tool-ev-line-chart {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.tool-ev-line-chart text {
  fill: var(--ink-muted);
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 10px;
}

.tool-line-axis {
  stroke: var(--hairline);
  stroke-width: 1;
}

.tool-line-path {
  fill: none;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.tool-line-path--ev {
  stroke: var(--accent);
}

.tool-line-path--ice {
  stroke: var(--ink-muted);
}

.tool-line-current {
  fill: var(--accent);
  stroke: var(--surface);
  stroke-width: 2;
}

.tool-ev-line-chart .tool-line-value-label {
  fill: var(--ink);
  font-weight: 600;
}

.tool-line-chart-summary {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--ink-muted);
}

.tool-advanced {
  margin-top: 16px;
  border-top: 1px solid var(--hairline);
}

.tool-advanced summary {
  padding: 14px 0 4px;
  cursor: pointer;
  font-size: 14px;
  font-weight: 600;
}

/* ---- individual integration guide pages (website/integrations/<slug>.html) */
.guide-diagram {
  display: block;
  width: 100%;
  max-width: 600px;
  height: auto;
  margin: 4px auto 8px;
}

.guide-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin: 4px 0 0;
}

.guide-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink-muted);
  background: var(--surface);
  box-shadow: var(--card-shadow);
  border-radius: 999px;
  padding: 5px 12px;
}

.guide-checklist {
  width: 100%;
  box-sizing: border-box;
  text-align: left;
  background: var(--surface);
  border-radius: 14px;
  box-shadow:
    0 1px 3px rgba(27, 36, 86, 0.06),
    0 14px 32px rgba(27, 36, 86, 0.07);
  padding: 18px 20px 20px;
}

.guide-checklist h2 {
  font-size: 15px;
  margin: 0 0 12px;
}

.guide-checklist ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.guide-checklist li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink);
}

.guide-checklist li svg {
  flex: none;
  margin-top: 2px;
  color: var(--link);
}

.guide-steps {
  width: 100%;
  text-align: left;
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: step;
  display: flex;
  flex-direction: column;
}

.guide-step {
  position: relative;
  counter-increment: step;
  display: flex;
  gap: 16px;
  padding: 0 0 26px;
}

.guide-step:last-child {
  padding-bottom: 0;
}

.guide-step::before {
  content: counter(step);
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--ink);
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'IBM Plex Mono', monospace;
  font-weight: 600;
  font-size: 13px;
  position: relative;
  z-index: 1;
}

.guide-step:not(:last-child)::after {
  content: '';
  position: absolute;
  left: 14.25px;
  top: 30px;
  bottom: 0;
  width: 1.5px;
  background: var(--hairline);
}

.guide-step-body {
  padding-top: 4px;
}

.guide-step-body h3 {
  margin: 0 0 4px;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ink);
}

.guide-step-body p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--ink-muted);
}

.guide-step-body p + p {
  margin-top: 8px;
}

.guide-step-body code,
.guide-note code {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 0.92em;
  background: var(--bg);
  padding: 1px 5px;
  border-radius: 5px;
  color: var(--ink);
}

.guide-note {
  width: 100%;
  box-sizing: border-box;
  text-align: left;
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--surface);
  border-radius: 12px;
  box-shadow: var(--card-shadow);
  padding: 14px 16px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--ink-muted);
}

.guide-note svg {
  flex: none;
  margin-top: 1px;
  color: var(--link);
}

.guide-note strong {
  color: var(--ink);
}

.guide-crosslinks {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

.guide-crosslinks a {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(27, 36, 86, 0.06);
  border-radius: 999px;
  padding: 7px 14px;
}

.guide-crosslinks a:hover {
  color: var(--accent);
  filter: none;
}

/* Real screenshots of a partner's own site (e.g. myenergi's account
   portal), used sparingly where the exact live UI is worth showing
   directly rather than just described - always with a citation/date
   underneath, since a partner's own layout can change at any time. */
.guide-screenshots {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 14px;
  margin: 10px 0 4px;
}

.guide-screenshot {
  min-width: 0;
  margin: 0;
}

.guide-screenshot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 10px;
  box-shadow:
    0 1px 3px rgba(27, 36, 86, 0.08),
    0 10px 24px rgba(27, 36, 86, 0.1);
}

.guide-screenshot figcaption {
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--ink-muted);
  text-align: center;
}

@media (max-width: 560px) {
  .integration-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* ---- app-mock: a faithful, non-interactive recreation of the actual
   Setup > Connect modal (SetupPage/CredentialsModal.jsx +
   CredentialFields.jsx/ChargerCredentialFields.jsx), not a screenshot -
   there's no build step on this site to keep a binary screenshot in sync
   with the real UI, so this is plain markup styled with the site's own
   tokens instead. Every label/placeholder/button word below is copied
   verbatim from that component, not paraphrased, so it stays literally
   what a visitor will see once they're on that screen. */
.app-mock {
  width: 100%;
  max-width: 380px;
  margin: 4px auto 8px;
  box-sizing: border-box;
  text-align: left;
  background: var(--surface);
  border-radius: 16px;
  box-shadow:
    0 20px 44px rgba(27, 36, 86, 0.16),
    0 2px 6px rgba(27, 36, 86, 0.07);
  padding: 18px;
}

.app-mock-title {
  font-family: 'Fraunces', serif;
  font-weight: 600;
  font-size: 15px;
  color: var(--ink);
  margin: 0 0 10px;
}

.app-mock-help {
  font-size: 11.5px;
  line-height: 1.6;
  color: var(--ink-muted);
  background: var(--bg);
  border-radius: 10px;
  padding: 10px 11px;
  margin-bottom: 12px;
}

.app-mock-help strong {
  color: var(--ink);
}

.app-mock-help span {
  color: var(--link);
}

.app-mock-label {
  display: block;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 11.5px;
  color: var(--ink-muted);
  margin-bottom: 4px;
}

.app-mock-field {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 12px;
  color: var(--ink-muted);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 8px 10px;
  margin-bottom: 10px;
  background: #ffffff;
}

.app-mock-field:last-of-type {
  margin-bottom: 4px;
}

.app-mock-actions {
  display: flex;
  gap: 8px;
  margin-top: 10px;
}

.app-mock-btn {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 11.5px;
  border-radius: 9px;
  padding: 7px 13px;
  border: 1px solid var(--hairline);
  color: var(--ink);
  background: #ffffff;
}

.app-mock-btn--primary {
  background: var(--ink);
  color: #ffffff;
  border: none;
}

.app-mock-caption {
  text-align: center;
  font-size: 11.5px;
  color: var(--ink-muted);
  margin: 10px 0 0;
}

.app-mock-caption svg {
  vertical-align: -2px;
  margin-right: 3px;
  color: var(--link);
}

/* ---- free tools (website/tools/) - real interactive forms, unlike the
   rest of this static site. Visually related to .app-mock (same field/
   label recipe) but genuinely interactive, so real :focus states etc. */
.roi-tool {
  width: 100%;
  max-width: 480px;
  margin: 8px auto 0;
  box-sizing: border-box;
  text-align: left;
  background: var(--surface);
  border-radius: 16px;
  box-shadow:
    0 1px 3px rgba(27, 36, 86, 0.06),
    0 14px 32px rgba(27, 36, 86, 0.07);
  padding: 22px 22px 24px;
}

.roi-tool:has(.tool-input-section) {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-width: 760px;
}

.tool-input-section {
  border: 1px solid rgba(40, 54, 118, 0.14);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.68);
  padding: 0 18px;
}

.tool-input-section > summary {
  cursor: pointer;
  list-style: none;
  padding: 17px 30px 17px 0;
  color: var(--ink);
  font-size: 17px;
  font-weight: 750;
  position: relative;
}

.tool-input-section > summary::-webkit-details-marker {
  display: none;
}

.tool-input-section > summary::after {
  content: '+';
  position: absolute;
  right: 0;
  top: 14px;
  color: var(--accent);
  font-size: 24px;
  line-height: 1;
}

.tool-input-section[open] > summary::after {
  content: '−';
}

.tool-input-section[open] {
  padding-bottom: 18px;
}

.tool-input-section--system[open] {
  display: flex;
  flex-direction: column;
}

.tool-input-section--system > summary {
  order: 0;
}
.tool-input-section--system > .system-inverter {
  order: 1;
}
.tool-input-section--system > .system-inverter-type {
  order: 2;
}
.tool-input-section--system > .system-loss {
  order: 3;
}
.tool-input-section--system > .system-export-limit {
  order: 4;
}
.tool-input-section--system > .system-battery-toggle {
  order: 5;
}
.tool-input-section--system > .system-battery-fields {
  order: 6;
}

.system-battery-fields:not([hidden]) {
  display: flex;
  flex-direction: column;
}

.system-battery-fields > .roi-row:nth-child(2) {
  order: 1;
}

.system-battery-fields > .roi-row:nth-child(3) {
  order: 2;
}

.system-battery-fields > .roi-row:nth-child(1) {
  order: 3;
}

.tool-input-section--existing {
  order: 1;
}
.tool-input-section--usage {
  order: 2;
}
.tool-input-section--solar {
  order: 3;
}
.tool-input-section--system {
  order: 4;
}
.tool-input-section--variables {
  order: 5;
}
.tool-input-section--financials {
  order: 6;
}
.roi-tool > .roi-submit {
  order: 7;
}
.roi-tool > .roi-error {
  order: 8;
}
.roi-tool > .roi-results {
  order: 9;
}

.roi-field {
  margin-bottom: 14px;
}

.roi-row {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.roi-row .roi-field {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-width: 0;
}

.roi-row .roi-label {
  display: flex;
  align-items: flex-end;
  min-height: 3em;
}

[data-comb-form] [data-comb-current-multi] > .roi-field:first-child,
[data-comb-form] [data-comb-new-multi] > .roi-field:first-child {
  margin-bottom: 6px;
}

[data-comb-form] .tariff-rate-row .roi-field {
  margin-bottom: 8px;
}

[data-comb-form] .tariff-rate-row .roi-label {
  min-height: 1.75em;
}

[data-comb-form] .comb-tariff-usage-note {
  display: block;
  font-size: 11px;
  line-height: 1.5;
  margin: 0 0 14px;
}

.comb-usage-pattern-preview,
[data-comb-current-tariff-strip],
[data-comb-new-tariff-strip] {
  margin: 10px 0 6px;
}

.comb-pattern-bars {
  display: grid;
  /* 48 half hours (src/householdUsagePatterns.js), lined up with the
     tariff strip's 48 slots */
  grid-template-columns: repeat(48, minmax(0, 1fr));
  gap: 1px;
  align-items: end;
  height: 62px;
  padding: 7px 8px 0;
  border: 1px solid var(--hairline);
  border-radius: 8px 8px 0 0;
  background: rgba(255, 255, 255, 0.5);
}

.comb-pattern-bars span {
  display: block;
  min-width: 0;
  border-radius: 2px 2px 0 0;
  background: var(--accent);
}

.comb-tariff-slots {
  display: grid;
  grid-template-columns: repeat(48, minmax(0, 1fr));
  gap: 1px;
  overflow: hidden;
  border-radius: 7px;
  height: 22px;
  background: var(--hairline);
}

.comb-tariff-slot--1,
.comb-tariff-legend-item--1::before {
  background: var(--accent);
}
.comb-tariff-slot--2,
.comb-tariff-legend-item--2::before {
  background: var(--ink);
}
.comb-tariff-slot--3,
.comb-tariff-legend-item--3::before {
  background: var(--link);
}
.comb-tariff-slot--invalid {
  background: repeating-linear-gradient(
    45deg,
    var(--ink-muted) 0 4px,
    var(--hairline) 4px 8px
  );
}

.comb-export-limit-note {
  display: block;
  font-size: 11px;
  line-height: 1.5;
  margin: 0 0 7px;
}

.comb-finance-key {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin: 10px 0 8px;
  font:
    11px/1.5 'IBM Plex Sans',
    sans-serif;
  color: var(--ink-muted);
}
.comb-finance-key span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.comb-finance-key span::before {
  content: '';
  width: 16px;
  height: 3px;
  border-radius: 2px;
  background: var(--accent);
}
.comb-finance-key--bank::before {
  background: var(--ink) !important;
}
.comb-finance-chart {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}
.comb-finance-chart text {
  font:
    11px 'IBM Plex Sans',
    sans-serif;
  font-variant-numeric: tabular-nums;
  fill: var(--ink-muted);
}
.comb-finance-grid {
  stroke: var(--hairline);
  stroke-width: 1;
}
.comb-finance-line {
  fill: none;
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.comb-finance-line--solar {
  stroke: var(--accent);
}
.comb-finance-line--bank {
  stroke: var(--ink);
}
.comb-finance-chart-note {
  display: block;
  font-size: 11px;
  line-height: 1.5;
  margin-top: 6px;
}
.comb-financial-table {
  min-width: 570px;
}
.comb-projection-note {
  display: block;
  font-size: 11px;
  line-height: 1.5;
  margin-top: 7px;
}

.comb-timeline-axis {
  display: flex;
  justify-content: space-between;
  color: var(--ink-muted);
  font:
    10px/1.5 'IBM Plex Sans',
    sans-serif;
  font-variant-numeric: tabular-nums;
  margin-top: 3px;
}

.comb-tariff-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin-top: 7px;
}

.comb-tariff-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--ink-muted);
  font:
    11px/1.5 'IBM Plex Sans',
    sans-serif;
}

.comb-tariff-legend-item::before {
  content: '';
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 2px;
}

.comb-tariff-warning {
  display: block;
  margin-top: 4px;
}

.roi-label {
  display: block;
  font-family: 'IBM Plex Sans', sans-serif;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 5px;
}

.roi-hint {
  font-size: 11px;
  color: var(--ink-muted);
  margin-top: 4px;
  line-height: 1.5;
}

.roi-input,
.roi-select {
  width: 100%;
  min-height: 40px;
  box-sizing: border-box;
  padding: 9px 11px;
  border-radius: 8px;
  border: 1px solid var(--hairline);
  font-family: 'IBM Plex Sans', sans-serif;
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  color: var(--ink);
  background: #ffffff;
}

@media (max-width: 680px) {
  .tool-input-section {
    padding-inline: 14px;
  }

  .roi-row {
    display: block;
  }

  .roi-row.tariff-rate-row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
  }

  .tariff-rate-row .roi-label {
    min-height: 4.5em;
    align-items: flex-end;
    overflow-wrap: anywhere;
  }

  .tariff-rate-row .roi-input {
    padding-inline: 5px;
    font-size: 11px;
  }

  .roi-row .roi-field {
    width: 100%;
  }

  .roi-row .roi-label {
    min-height: 0;
  }

  .roi-row.tariff-rate-row .roi-label {
    min-height: 4.5em;
  }

  [data-comb-form] .tariff-rate-row .roi-label {
    min-height: 3.25em;
  }

  .roi-postcode-row {
    align-items: stretch;
  }
}

.roi-input:focus,
.roi-select:focus {
  outline: 2px solid var(--link);
  outline-offset: 1px;
}

.roi-postcode-row {
  display: flex;
  gap: 8px;
}

.roi-postcode-row .roi-input {
  flex: 1;
}

.roi-postcode-btn {
  flex: none;
  background: var(--bg);
  color: var(--ink);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 0 14px;
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 12.5px;
  cursor: pointer;
  white-space: nowrap;
}

.roi-postcode-btn:hover {
  background: var(--surface);
}

.roi-postcode-status {
  display: block;
  margin-top: 6px;
  font-size: 11.5px;
}

.roi-postcode-status[data-state='ok'] {
  color: var(--link);
}

.roi-postcode-status[data-state='error'] {
  color: var(--accent);
}

.roi-submit {
  width: 100%;
  background: var(--ink);
  color: #ffffff;
  border: none;
  border-radius: 10px;
  padding: 13px;
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 14.5px;
  cursor: pointer;
  margin-top: 4px;
}

.roi-submit:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.roi-error {
  margin-top: 10px;
  font-size: 12.5px;
  color: var(--accent);
}

.roi-results {
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1px solid var(--hairline);
}

.roi-result-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  padding: 7px 0;
}

.roi-result-label {
  font-size: 12.5px;
  color: var(--ink-muted);
}

.roi-result-value {
  font-family: 'IBM Plex Sans', sans-serif;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  white-space: nowrap;
}

/* A bill's home and car lines under its total (the battery-only page) */
.roi-result-row--sub {
  padding: 2px 0 2px 14px;
}
.roi-result-row--sub .roi-result-label,
.roi-result-row--sub .roi-result-value {
  font-size: 12px;
  color: var(--ink-muted);
}

.roi-result-row--headline {
  padding-top: 2px;
  padding-bottom: 12px;
  /* A long headline drops under its label on a phone rather than running
     off the card ("6 years and 2 months" at 375px, 1 Oct 2026). */
  flex-wrap: wrap;
  row-gap: 2px;
}

.roi-result-row--headline .roi-result-label {
  font-size: 13px;
  flex-shrink: 0;
}

.roi-result-row--headline .roi-result-value {
  font-family: 'Fraunces', serif;
  font-weight: 600;
  font-size: clamp(20px, 6.4vw, 24px);
  color: var(--accent);
  white-space: normal;
  text-align: right;
  line-height: 1.15;
  margin-left: auto;
  min-width: 0;
}

.roi-result-row--headline.roi-result-row--cost-increase .roi-result-value {
  color: #b42318;
}

/* The year's totals under a monthly table */
.tool-table-total td {
  font-weight: 600;
  border-top: 1px solid var(--hairline);
}

.roi-assumptions,
.roi-results-section {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--hairline);
  font-size: 11px;
  color: var(--ink-muted);
  line-height: 1.6;
}

/* One heading style for every block of calculator results, above the block
   (owner, 7 Oct 2026: four different styles, some under their charts) */
.roi-assumptions-title,
.roi-section-title {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.roi-assumptions ul {
  margin: 0;
  padding-left: 16px;
}

.roi-assumptions li {
  margin-bottom: 4px;
}

/* ---- array repeater (annual-generation-calculator.html) - up to 3 solar
   arrays, each its own collapsible-feeling block reusing the .roi-* field
   primitives above. */
.array-block {
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 14px 14px 4px;
  margin-bottom: 14px;
}

.array-block-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

.array-block-title {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 13.5px;
  color: var(--ink);
}

.array-remove-btn {
  background: none;
  border: none;
  padding: 0;
  color: var(--ink-muted);
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
}

.array-remove-btn:hover {
  color: var(--accent);
}

.array-add-btn {
  width: 100%;
  background: var(--bg);
  color: var(--ink);
  border: 1px dashed var(--hairline);
  border-radius: 10px;
  padding: 10px;
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  font-size: 12.5px;
  cursor: pointer;
  margin-bottom: 14px;
}

.array-add-btn:hover {
  background: var(--surface);
  border-color: var(--link);
}

.array-add-btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ---- results table (monthly generation breakdown) --------------------- */
.tool-table-wrap {
  width: 100%;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  margin-top: 4px;
}

.tool-table {
  width: 100%;
  min-width: 0;
  border-collapse: collapse;
  table-layout: fixed;
  font-size: 12.5px;
}

.tool-table--arrays-2 {
  min-width: 0;
}

.tool-table--arrays-3 {
  min-width: 0;
}

.tool-table th,
.tool-table td {
  padding: 7px 6px;
  text-align: right;
  border-bottom: 1px solid var(--hairline);
  white-space: nowrap;
}

.tool-table th:first-child,
.tool-table td:first-child {
  text-align: left;
  width: 52px;
}

.tool-table thead th {
  font-family: 'IBM Plex Sans', sans-serif;
  font-weight: 600;
  color: var(--ink);
  font-size: 11.5px;
  line-height: 1.25;
  white-space: normal;
  overflow-wrap: anywhere;
}

.tool-table tbody td {
  color: var(--ink-muted);
  font-family: 'IBM Plex Sans', sans-serif;
  font-variant-numeric: tabular-nums;
}

.tool-table tbody td:first-child {
  color: var(--ink);
  font-family: 'IBM Plex Sans', sans-serif;
}

.tool-table tfoot td {
  font-weight: 700;
  color: var(--ink);
  border-bottom: none;
  border-top: 2px solid var(--hairline);
}

/* ---- simple hand-rolled line chart (battery-payback-calculator.html) -
   no charting library, same "plain SVG" approach as every other chart on
   this site. */
.tool-chart-wrap {
  width: 100%;
  margin-top: 14px;
}

.tool-chart-wrap svg {
  display: block;
  width: 100%;
  height: auto;
}

.tool-chart-legend {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 8px;
  font-size: 11.5px;
  color: var(--ink-muted);
}

.tool-chart-legend-item {
  display: flex;
  align-items: center;
  gap: 6px;
}

.tool-chart-swatch {
  width: 14px;
  height: 3px;
  border-radius: 2px;
  flex: none;
}

/* "stop using these silly text boxes with arrows to increase a value...
   keep it simple. I want rid of them from everywhere" - PROJECT_BRIEF.md
   2026-09-08, direct feedback. No number input exists on this site
   today, but the same global rule as web/ and admin/ so any future one
   never grows the spinner UI back by default. */
input[type='number']::-webkit-outer-spin-button,
input[type='number']::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
input[type='number'] {
  -moz-appearance: textfield;
}

.tool-heat-chart {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 4px;
  min-height: 180px;
  padding-top: 8px;
}

.tool-heat-chart-item {
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 5px;
  min-width: 0;
  text-align: center;
}

.tool-heat-chart-values {
  color: var(--ink-muted);
  font-family: 'IBM Plex Sans', sans-serif;
  font-variant-numeric: tabular-nums;
  font-size: clamp(7px, 1.8vw, 9px);
  white-space: nowrap;
}

.tool-heat-chart-bars {
  align-items: end;
  border-bottom: 1px solid var(--hairline);
  display: flex;
  gap: 2px;
  height: 116px;
  justify-content: center;
}

.tool-heat-chart-bars i {
  border-radius: 3px 3px 0 0;
  display: block;
  width: min(10px, 38%);
}

.tool-heat-current {
  background: var(--ink-muted);
}

.tool-heat-pump {
  background: var(--accent);
}

/* Charts and diagrams inside a post: the title lives in the caption (the
   site's own font), not inside the image, so a blog card showing the same
   image doesn't read like a second post title. */
.post-figure {
  max-width: 420px;
  margin: 8px auto 28px;
}

.post-figure img {
  display: block;
  width: 100%;
  height: auto;
}

.post-figure figcaption {
  margin-top: 8px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-muted);
  text-align: center;
}

/* A real app screenshot inside a post, framed like the integration
   guides' screenshots so it reads as a picture of the app. */
.post-figure--screenshot img {
  max-width: 360px;
  margin: 0 auto;
  border-radius: 12px;
  background: var(--surface);
  box-shadow:
    0 1px 3px rgba(27, 36, 86, 0.08),
    0 10px 24px rgba(27, 36, 86, 0.1);
}

/* A tall phone screenshot shown small beside the text, so it sits in
   the article like a magazine picture rather than a full-width block.
   Stacks under the text on narrow screens. */
.post-figure--float {
  float: right;
  width: 190px;
  margin: 4px 0 12px 22px;
}

.post-figure--float img {
  border-radius: 14px;
  box-shadow:
    0 1px 3px rgba(27, 36, 86, 0.08),
    0 10px 24px rgba(27, 36, 86, 0.12);
}

.post-figure--float figcaption {
  font-size: 11.5px;
}

.page section:has(.post-figure--float)::after {
  content: '';
  display: block;
  clear: both;
}

@media (max-width: 560px) {
  .post-figure--float {
    float: none;
    width: 220px;
    margin: 8px auto 24px;
  }
}

/* A tall (portrait) image on a blog card - the UK map - shown narrower
   and centred so the card isn't dominated by it. */
.post-card img.post-card-img--portrait {
  width: 45%;
  max-width: 200px;
  margin: 0 auto 14px;
}

/* The logo of the company a post is about, under the title. Official
   artwork, unmodified, kept small - it identifies the company, it
   doesn't decorate the page. */
.post-brand-logo {
  display: block;
  box-sizing: content-box;
  width: auto;
  height: 28px;
  margin: 14px 0 0;
  padding: 10px 14px;
  background: #ffffff;
  border-radius: 12px;
  box-shadow: var(--card-shadow);
}

.post-brand-logo--tall {
  height: 48px;
  padding: 8px 12px;
}
