/* ============================================================================
 * solar_demo.css — the anonymous solar estimator at /solar-designer/demo/
 * ============================================================================
 *
 * A file of its own rather than more `.lp-*` in ui.css: this page has one
 * bespoke control (the city combobox) and one bespoke pattern (the units
 * toggle driving two input panes), neither of which any other page wants. It
 * loads only where it is used.
 *
 * It DOES NOT introduce a second look. The page renders inside the `.lp-page`
 * marketing shell, which already sets the palette, the type, the 12/20/30px
 * radii and the pill-with-arrow-badge button — so everything below is built
 * from the same tokens the shell redefines (`--brand`, `--surface-*`,
 * `--radius-*`), and the call-to-action is the shell's own `.btn-primary`
 * rather than a lookalike. Change the shell and this page follows.
 *
 * The one local colour is amber. `.product-solar` sets `--brand` to amber-500,
 * which is right for a 16px icon and quite wrong as a button fill under white
 * text (2.1:1), and in any case the shell's `.lp-page` wins that cascade. So
 * amber lives here as an explicit accent for icons and the hero wash only, and
 * every filled surface stays on the shell's blue.
 * ========================================================================= */

.sd-scope {
  --sd-accent:      var(--amber-500);
  --sd-accent-soft: var(--amber-100);
  --sd-focus-ring:  rgba(59, 130, 246, .22);
}

/* ---------------------------------------------------------------------------
 * HERO + PHOTO BACKDROP
 *
 * A rooftop array behind the ask, washed almost to white and bleeding down
 * past the hero so it reads as the page's ground rather than a banner pasted
 * on top of it.
 *
 * Legibility is not left to chance. Three things guarantee it:
 *   - the photo carries `opacity: .18`, so at most 18% of its own contrast
 *     survives against the white beneath it;
 *   - a scrim sits between the photo and the text, lifting the band the
 *     heading occupies back toward white;
 *   - the text is in a `z-index: 1` layer, so nothing can ever land over it.
 * Measured against `--ink` (#101a3a) the heading clears 12:1 — well past the
 * 4.5:1 floor, with room for the photo to be swapped for a darker one.
 *
 * The stacking is load-bearing and easy to break. `.sd-hero` is
 * `position: relative`, so it paints in the positioned step — LATER than any
 * negative-z child. Give it a background of its own and it covers both layers
 * below. That is why `.lp-page .lp-hero`'s opaque white is reset here rather
 * than left to fight them, and why `overflow` must stay visible: the backdrop
 * is deliberately taller than the hero.
 *
 * The `.lp-page` prefix on the reset is required, not decorative: the rule it
 * has to beat is `.lp-page .lp-hero`, and a bare `.sd-hero` loses that on
 * specificity no matter which file loads last.
 * ------------------------------------------------------------------------ */
.lp-page .sd-hero {
  /* How far the backdrop bleeds past the hero, shared by both layers so the
     photo and its scrim can never fade out of step. */
  --sd-backdrop-h: calc(100% + 30rem);

  position: relative;
  background: transparent;   /* resets .lp-page .lp-hero's opaque white */
  border-bottom: 0;
  overflow: visible;         /* resets .lp-hero's clip */
}

/* Layer 1 — the photograph. */
.sd-hero::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: var(--sd-backdrop-h);
  z-index: -2;
  pointer-events: none;
  background: url("../images/solar-install-backdrop.5265284b47d3.jpg") center 38% / cover no-repeat;
  opacity: .22;
  /* Fades the photo out rather than cutting it off. The scrim below also ends
     opaque, so browsers without mask support still get a clean edge. */
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 46%, transparent 96%);
          mask-image: linear-gradient(180deg, #000 0%, #000 46%, transparent 96%);
}

/* Layer 2 — the scrim, plus the warm wash that keeps the page reading solar. */
.sd-hero::after {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: var(--sd-backdrop-h);
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(56rem 26rem at 50% -8%, rgba(245, 158, 11, .17), transparent 66%),
    linear-gradient(180deg,
        rgba(255, 255, 255, .46) 0%,
        rgba(255, 255, 255, .40) 34%,
        rgba(255, 255, 255, .62) 70%,
        var(--surface) 100%);
}

.sd-hero > * { position: relative; z-index: 1; }

/* ---------------------------------------------------------------------------
 * HEADLINE
 * Two thoughts, not one sentence: what the product does, then the question the
 * visitor arrived with. The second is smaller and in a different colour so it
 * reads as a follow-on rather than a competing headline.
 *
 * The colour comes from the shell's existing `.lp-hero__accent`, which is the
 * two-tone-headline idiom the router page already uses — `--shine-accent-ink`
 * (#1d4ed8), the accent cut for reading at 6.3:1 rather than the #3b82f6 fill,
 * which manages only 3:1. Only the size and the line break belong here.
 *
 * `max-width` needs the `.lp-page` prefix to clear `.lp-page .lp-hero__title`'s
 * 18ch, which would otherwise break "Design Your Home Solar System." into three
 * ragged lines.
 * ------------------------------------------------------------------------ */
.lp-page .sd-title { max-width: 100%; text-wrap: balance; }

.sd-title__ask {
  display: block;
  margin-top: .3em;
  font-size: .52em;
  line-height: 1.15;
}

.sd-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: .4rem .9rem;
  margin-bottom: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface-raised);
  box-shadow: var(--shadow-sm);
  font-size: .82rem;
  font-weight: 500;
  color: var(--text-muted);
}

.sd-eyebrow i { color: var(--sd-accent); }

/* ---------------------------------------------------------------------------
 * FORM SHELL
 * ------------------------------------------------------------------------ */
.sd-form {
  position: relative;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: visible;   /* the combobox menu escapes the card */
}

/* The one place solar amber is load-bearing: a hairline that says which
   product you are in without spending contrast on it. */
.sd-form::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 3px;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  background: linear-gradient(90deg,
              var(--amber-500) 0%, var(--amber-600) 45%, var(--brand) 100%);
}

.sd-form__body {
  display: grid;
  gap: var(--space-5);
  padding: var(--space-6) var(--space-4) var(--space-5);
}

@media (min-width: 36rem) {
  .sd-form__body { padding: var(--space-6); }
}

.sd-row {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr;
}

/* Country and City side by side once there is room for both labels on one
   line each — below that they stack rather than truncate. */
@media (min-width: 34rem) {
  .sd-row { grid-template-columns: 1fr 1fr; }
}

.sd-field { display: grid; gap: var(--space-2); align-content: start; min-width: 0; }

.sd-field__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}

.sd-label {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  font-size: .92rem;
  font-weight: 600;
  color: var(--text);
  margin: 0;
}

.sd-label i { color: var(--sd-accent); font-size: .95rem; }

.sd-label__optional {
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--text-subtle);
  padding: .1rem .45rem;
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
}

.sd-help {
  margin: 0;
  font-size: .8rem;
  line-height: 1.45;
  color: var(--text-muted);
}

/* ---------------------------------------------------------------------------
 * CONTROLS
 * Styled here rather than borrowed from Bootstrap because this page ships
 * 5.3.2 while the rest of the shell is on digalu's 5.1.3 — a control that
 * looks the same under both is one less thing that breaks when the theme
 * finally converges.
 * ------------------------------------------------------------------------ */
.sd-control {
  width: 100%;
  padding: .75rem .95rem;
  font-family: inherit;
  font-size: 1rem;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
  appearance: none;
}

.sd-control::placeholder { color: var(--text-subtle); }

.sd-control:hover { border-color: var(--border-strong); }

.sd-control:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 4px var(--sd-focus-ring);
}

.sd-control:disabled { opacity: .55; cursor: not-allowed; }

/* Native select arrow, drawn so it matches the combobox caret exactly. */
.sd-select {
  padding-inline-end: 2.5rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%233d4468' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .95rem center;
  background-size: 1rem;
  cursor: pointer;
}

/* ---------------------------------------------------------------------------
 * CITY COMBOBOX
 * A text input that filters as you type, over a list scoped to the country
 * already chosen. Not a <select>: the city list runs to a dozen entries per
 * market and typing three letters beats scrolling. Not a bare <datalist>
 * either — that renders as unstyled browser chrome and is silently absent on
 * some mobile browsers.
 * ------------------------------------------------------------------------ */
.sd-combo { position: relative; }

.sd-combo__input { padding-inline-end: 2.5rem; }

.sd-combo__caret {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: .4rem;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-muted);
  cursor: pointer;
  transition: transform var(--dur-fast) ease, color var(--dur-fast) ease;
}

.sd-combo__caret:hover { color: var(--text); }

.sd-combo.is-open .sd-combo__caret { transform: translateY(-50%) rotate(180deg); }

.sd-combo__menu {
  position: absolute;
  inset-block-start: calc(100% + .35rem);
  inset-inline: 0;
  z-index: 30;
  max-height: 15rem;
  overflow-y: auto;
  margin: 0;
  padding: .3rem;
  list-style: none;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}

.sd-combo__menu[hidden] { display: none; }

.sd-combo__option {
  padding: .55rem .7rem;
  border-radius: var(--radius-sm);
  font-size: .95rem;
  color: var(--text);
  cursor: pointer;
}

.sd-combo__option:hover,
.sd-combo__option.is-active { background: var(--brand-subtle); }

.sd-combo__option[aria-selected="true"] { font-weight: 600; }

/* The matched characters, so a filtered list shows WHY each row is in it. */
.sd-combo__option mark {
  padding: 0;
  background: var(--sd-accent-soft);
  color: inherit;
  border-radius: 2px;
}

.sd-combo__empty {
  padding: .6rem .7rem;
  font-size: .85rem;
  color: var(--text-muted);
}

/* ---------------------------------------------------------------------------
 * USAGE: units toggle + the two input panes
 * ------------------------------------------------------------------------ */
.sd-field--usage {
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
  gap: var(--space-3);
}

.sd-toggle {
  display: inline-flex;
  padding: 3px;
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--surface);
}

/* Visually hidden, not display:none — the radio must stay focusable or the
   toggle becomes unreachable by keyboard. */
.sd-toggle input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.sd-toggle label {
  min-width: 3.7rem;
  padding: .32rem .85rem;
  border-radius: var(--radius-pill);
  font-size: .82rem;
  font-weight: 600;
  text-align: center;
  color: var(--text-muted);
  cursor: pointer;
  user-select: none;
  transition: background var(--dur-fast) ease, color var(--dur-fast) ease;
}

.sd-toggle label:hover { color: var(--text); }

.sd-toggle input:checked + label {
  background: var(--brand);
  color: var(--brand-contrast);
}

.sd-toggle input:focus-visible + label {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.sd-pane { display: grid; gap: var(--space-2); }
.sd-pane[hidden] { display: none; }

/* The unit sits inside the field's border rather than beside it, so which
   currency a figure is being typed in is never more than a glance away. */
.sd-inputgroup {
  display: flex;
  align-items: stretch;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: border-color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

.sd-inputgroup:focus-within {
  border-color: var(--brand);
  box-shadow: 0 0 0 4px var(--sd-focus-ring);
}

.sd-inputgroup__unit,
.sd-inputgroup__suffix {
  display: grid;
  place-items: center;
  padding-inline: .95rem;
  font-size: .88rem;
  font-weight: 600;
  color: var(--text-muted);
  white-space: nowrap;
}

.sd-inputgroup__unit {
  min-width: 3.2rem;
  color: var(--text);
  border-inline-end: 1px solid var(--border);
}

.sd-inputgroup__suffix { border-inline-start: 1px solid var(--border); }

.sd-inputgroup__input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  font-size: 1.15rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.sd-inputgroup__input:hover,
.sd-inputgroup__input:focus { border: 0; box-shadow: none; }

/* Spinners are noise on a "roughly how much" field and shrink the tap target. */
.sd-inputgroup__input::-webkit-outer-spin-button,
.sd-inputgroup__input::-webkit-inner-spin-button { appearance: none; margin: 0; }
.sd-inputgroup__input[type="number"] { -moz-appearance: textfield; }

/* The shell's pill button already carries the arrow badge; this only makes it
   fill the card and keeps the label off the left edge. */
.lp-page .sd-form .btn-primary { width: 100%; justify-content: center; }

/* ---------------------------------------------------------------------------
 * MESSAGES + RESULT
 * ------------------------------------------------------------------------ */
.sd-alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
  border: 1px solid var(--amber-500);
  border-inline-start-width: 4px;
  border-radius: var(--radius-md);
  background: var(--amber-100);
  color: var(--text);
  font-size: .92rem;
}

.sd-alert i { color: var(--amber-600); margin-top: .12rem; }

.sd-meter {
  margin: var(--space-3) 0 0;
  font-size: .85rem;
  color: var(--text-subtle);
  text-align: center;
}

.sd-card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: var(--space-5) var(--space-4);
}

@media (min-width: 36rem) { .sd-card { padding: var(--space-6); } }

.sd-card__eyebrow {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  margin: 0 0 var(--space-4);
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--text-subtle);
}

.sd-card__place {
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
  color: var(--text-muted);
}

.sd-card__place i { color: var(--sd-accent); }

/* Grid, not a flex wrap: as flex items the tiles size to their own text, so
   "Panels / 12" ends up a third the width of "Pays for itself in / 6.4 yrs"
   and the row reads as four unrelated boxes rather than one figure set. */
.sd-stats {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
}

/* The tiles sit inside a raised card, so they step DOWN to read as tiles. */
.sd-stats .ui-stat {
  background: var(--surface-sunken);
  border-color: transparent;
  gap: 0;
}

.sd-stats .ui-stat__icon { color: var(--sd-accent); margin-bottom: var(--space-1); }
.sd-stats .ui-stat__value { font-size: 1.5rem; font-weight: 700; letter-spacing: -.01em; }
.sd-stats .ui-stat__label { font-size: .8rem; }

.sd-cta-card { text-align: center; }

.sd-cta-card h2 { font-size: clamp(1.3rem, 3vw, 1.7rem); margin-bottom: var(--space-3); }

.sd-cta-card p { color: var(--text-muted); font-size: .95rem; max-width: 40ch; margin-inline: auto; }

/* Wider than the 40ch the centred card gives its other paragraphs — this one
   is a lead-in over a two-column list, and 40ch above it reads as a column
   that has lost its neighbours. */
.sd-cta-card__lead { max-width: 56ch !important; margin-bottom: var(--space-5); }

.sd-cta-card__carry {
  margin: var(--space-5) auto var(--space-4);
  font-size: .88rem;
  color: var(--text-subtle);
  max-width: 46ch !important;
}

/* ---------------------------------------------------------------------------
 * BENEFITS LIST
 * Two columns from 40rem up. Six single-column rows push the button off the
 * bottom of a laptop screen, and a call to action you have to scroll to find
 * is one you did not make.
 * ------------------------------------------------------------------------ */
.sd-benefits {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-4);
  /* The card centres its text; a bullet list read centred is unreadable, so
     this opts back out for its own subtree. */
  text-align: start;
}

@media (min-width: 40rem) {
  .sd-benefits {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-5) var(--space-5);
  }
}

.sd-benefits li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-3);
  align-items: start;
}

/* Green, matching the outcome ticks on the result card above: the same mark
   means the same thing on both, which is what makes the wall read as "here is
   what comes next" rather than a different kind of list. */
.sd-benefits > li > i {
  color: var(--success);
  font-size: 1.05rem;
  line-height: 1.4;
}

.sd-benefits strong {
  display: block;
  margin-bottom: .15rem;
  font-weight: 600;
  font-size: .95rem;
  color: var(--text);
}

.sd-benefits span {
  display: block;
  font-size: .87rem;
  line-height: 1.5;
  color: var(--text-muted);
}

.sd-finewrite { font-size: .84rem; color: var(--text-subtle); }

/* ---------------------------------------------------------------------------
 * VISUAL PREVIEW — diagram + installation photo
 *
 * Sits below the estimate flow, always visible regardless of form/result/gate
 * state. Two panels of equal weight: the left is the same animated SVG a real
 * design gets (DiagramAgent.sample_flow_svg — dark theme, built to sit on its
 * own dark card rather than the page's white), the right is a real photo, so
 * one answers "how does this work" and the other "what does it actually look
 * like" side by side.
 * ------------------------------------------------------------------------ */
.sd-visual {
  padding-top: var(--space-10);
  padding-bottom: var(--space-10);
}

.sd-visual__grid {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
}
@media (min-width: 56rem) {
  /* No `align-items: start` here (deliberately) — grid's default `stretch`
     is what makes both columns share one row height, so the diagram and the
     photo stack opposite it end at the same bottom edge instead of the
     shorter column trailing off early. */
  .sd-visual__grid { grid-template-columns: 1fr 1fr; }
}

/* Each panel is a column in its own right: heading block first, then a media
   area that soaks up whatever height the grid gives the panel (the diagram
   card on desktop, or the photo stack). `height: 100%` only matters once the
   grid actually stretches both columns to equal height — on the single-column
   mobile layout there's no shared row height to fill, so it's scoped to the
   same breakpoint as the two-column grid above. */
.sd-visual__panel {
  min-width: 0;
  display: flex;
  flex-direction: column;
}
@media (min-width: 56rem) {
  .sd-visual__panel { height: 100%; }
}

.sd-visual__kicker {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-2);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--sd-accent);
}

.sd-visual__title {
  margin: 0 0 var(--space-2);
  font-size: 1.4rem;
  line-height: 1.25;
  color: var(--text);
}

.sd-visual__sub {
  margin: 0 0 var(--space-4);
  font-size: .92rem;
  line-height: 1.55;
  color: var(--text-muted);
  max-width: 34rem;
}

/* The diagram SVG is a dark-theme graphic — a light card behind it would fight
   its own background, so this card goes dark deliberately, unlike every other
   surface on the page. */
.sd-visual__diagram {
  flex: 1 1 auto;
  min-height: 20rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: #0a0f1e;
  border: 1px solid var(--border);
  box-shadow: 0 12px 32px -12px rgba(15, 23, 42, .35);
}
/* `height: 100%` (not `auto`) lets the SVG fill whatever the flexed card
   above gives it — its own `preserveAspectRatio` default (xMidYMid meet)
   still scales it undistorted, just centred within that box instead of
   dictating the box's height off its own intrinsic 900:880 ratio. Any
   letterboxed edge is invisible: `#0a0f1e` is the same colour the SVG's own
   background gradient settles to. */
.sd-visual__diagram svg { display: block; width: 100%; height: 100%; }

/* Two photos, equal shares of whatever height the grid gives this column —
   see .sd-visual__panel above for where that height comes from. */
.sd-visual__photos {
  flex: 1 1 auto;
  min-height: 20rem;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.sd-visual__photo {
  display: block;
  flex: 1 1 0;
  min-height: 9rem;
  width: 100%;
  object-fit: cover;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  box-shadow: 0 12px 32px -12px rgba(15, 23, 42, .35);
}
