/* Calculator A — per-lead database value page (/for/<slug>/).
   Extends solar.css. Same tokens, same hues; no colour literals.
   Chart colours come from the validated sequential ramp in tokens.css. */

.calc-eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-ghost);
  margin: 0 0 var(--space-2);
}

.calc-h {
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  color: var(--text-muted);
  letter-spacing: 0.02em;
  margin: 0 0 var(--space-3);
  padding: 0;
  border: 0;
}

/* ---------- Inputs ---------- */

.calc-input {
  margin: var(--space-8) 0;
  padding: var(--space-5);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

.field-row { margin-top: var(--space-4); }

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

.calc-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  position: relative;
}

.calc-label {
  font-size: var(--text-sm);
  color: var(--text-secondary);
}

.calc-num {
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  color: var(--text-primary);
  background: var(--bg-root);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  padding: var(--space-3);
  min-height: var(--tap-min);
  width: 100%;
  transition: border-color var(--duration-fast) var(--ease-smooth);
}

.calc-num:hover { border-color: var(--border-hover); }

.calc-num:focus-visible {
  outline: none;
  border-color: var(--accent-border);
  box-shadow: var(--glow-accent);
}

.calc-suffix {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--text-ghost);
  margin-left: var(--space-1);
}

/* ---------- Output ---------- */

.calc-out { margin: var(--space-8) 0; }

/* The one display-type moment on this page (bible §4). */
.calc-total {
  font-size: var(--text-hero);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  letter-spacing: -0.03em;
  color: var(--text-primary);
  margin: 0;
  font-variant-numeric: tabular-nums;
}

.calc-total-note {
  font-size: var(--text-sm);
  color: var(--text-ghost);
  margin: var(--space-2) 0 var(--space-5);
}

/* ---------- Stacked bar ----------
   Part-to-whole rides on a stacked bar, not a pie: the four category names are
   long, the segments must be clickable, and bars carry magnitude as well as
   proportion. 2px surface gaps between fills per the dataviz mark spec. */
.calc-bar {
  display: flex;
  gap: 2px;
  height: 14px;
  margin: 0 0 var(--space-5);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--bg-surface);
}

.calc-seg {
  flex-basis: 0;
  min-width: 2px;
  transition: flex-grow var(--duration-medium) var(--ease-smooth);
}

@media (prefers-reduced-motion: reduce) {
  .calc-seg { transition: none; }
}

/* ---------- Line rows ---------- */

.calc-lines {
  list-style: none;
  margin: 0 0 var(--space-6);
  padding: 0;
}

.calc-lines li { margin: 0; }

.calc-line {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  min-height: var(--tap-min);
  border-bottom: 1px solid var(--border-subtle);
  text-decoration: none;
  position: relative;
  /* Not the prose wipe: this is a block row, same treatment as .play. */
  background-image: none;
}

.calc-line::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--duration-medium) var(--ease-smooth);
}

.calc-line:hover::after,
.calc-line:focus-visible::after { transform: scaleX(1); }

.calc-swatch {
  width: 10px;
  height: 10px;
  border-radius: 2px;
  flex: none;
}

.calc-line-name {
  font-size: var(--text-sm);
  color: var(--text-primary);
}

.calc-line-val {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

.calc-line-pct {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-ghost);
  font-variant-numeric: tabular-nums;
  min-width: 3ch;
  text-align: right;
}

.calc-line-go {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-ghost);
  white-space: nowrap;
  transition: color var(--duration-fast) var(--ease-smooth);
}

.calc-line:hover .calc-line-go,
.calc-line:focus-visible .calc-line-go { color: var(--accent); }

/* ---------- Presets ---------- */

.calc-presets {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.calc-preset-label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-ghost);
  margin-right: var(--space-2);
}

.preset,
.calc-action {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  color: var(--text-muted);
  background: none;
  border: 1px solid var(--border-default);
  border-radius: var(--radius-md);
  padding: 0 var(--space-3);
  min-height: var(--tap-min);
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-smooth),
              border-color var(--duration-fast) var(--ease-smooth);
}

.preset:hover, .preset:focus-visible,
.calc-action:hover, .calc-action:focus-visible {
  color: var(--accent);
  border-color: var(--accent-border);
}

.preset[aria-pressed="true"] {
  color: var(--accent);
  border-color: var(--accent-border);
  background: var(--accent-bg);
}

/* ---------- Assumptions ---------- */

.calc-assume {
  margin: var(--space-6) 0;
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-subtle);
}

.calc-assume summary {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  cursor: pointer;
  min-height: var(--tap-min);
  display: flex;
  align-items: center;
}

.calc-assume summary:hover { color: var(--accent); }

.calc-mini {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--text-primary);
  background: var(--bg-root);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-2);
  width: 6.5ch;
}

.calc-mini:focus-visible {
  outline: none;
  border-color: var(--accent-border);
}

.calc-actions {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin: var(--space-6) 0;
}

/* ---------- Sources ---------- */

.calc-sources {
  margin-top: var(--space-10);
  padding-top: var(--space-6);
  border-top: 1px solid var(--border-subtle);
}

.calc-sources ol {
  padding-left: var(--space-5);
  font-size: var(--text-sm);
}

.calc-sources li { color: var(--text-ghost); margin-bottom: var(--space-2); }

.calc-sources li a { color: var(--text-muted); }

.calc-sources li:target a { color: var(--accent); }

.calc-disclaimer {
  font-size: var(--text-sm);
  color: var(--text-ghost);
  margin-top: var(--space-5);
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- Responsive ---------- */

@media (max-width: 480px) {
  .field-row--split { grid-template-columns: 1fr; }

  .calc-line {
    grid-template-columns: auto 1fr auto;
    row-gap: var(--space-1);
  }
  .calc-line-pct { display: none; }
  .calc-line-go { grid-column: 2 / -1; }
}

/* ---------- Print / PDF ----------
   The page is a deliverable they keep, so printing must produce the numbers,
   not a dark rectangle. Controls drop; content stays. */
@media print {
  .calc-actions,
  .calc-presets,
  .crumb { display: none; }

  .calc-assume { display: block; }
  .calc-assume summary { display: none; }

  .calc-input,
  .calc-bar { background: none; border: 1px solid currentColor; }
}

/* ---------- Partner table (per-lead rev-share calculators) ----------
   Named-partner rows are the personalization, so the table is the primary
   content rather than a supporting detail. Scrolls inside its own container so
   the page body never scrolls sideways at 320px. */

.partners { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }

.partners th {
  text-align: left;
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border-default);
  color: var(--text-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}

.partners td {
  padding: var(--space-2) var(--space-3);
  border-bottom: 1px solid var(--border-subtle);
  vertical-align: middle;
}

.p-name { color: var(--text-primary); font-weight: var(--weight-medium); white-space: nowrap; }
.p-trade { color: var(--text-ghost); font-size: var(--text-xs); white-space: nowrap; }

.p-val {
  font-family: var(--font-mono);
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

/* Inbound is the column the page exists to make visible — one returned install
   outweighs many outbound commissions, and that asymmetry IS the argument. */
.p-val--strong { color: var(--accent); font-weight: var(--weight-medium); }

.partners .calc-mini { width: 7ch; }

/* Two totals, deliberately unequal in weight: inbound is the finding, outbound
   is the thing everyone already assumes. */
.split {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: var(--space-5);
  margin: var(--space-6) 0;
  align-items: start;
}

.split-label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-ghost);
  margin: 0 0 var(--space-2);
}

.split-primary .calc-total { color: var(--text-primary); }

.split-secondary .calc-total {
  font-size: var(--text-xl);
  color: var(--text-secondary);
}

@media (max-width: 480px) {
  .split { grid-template-columns: 1fr; gap: var(--space-5); }
  .p-trade { display: none; }
}

/* ---------- Wide scrollable table ----------
   Seven columns do not fit the 48rem prose measure, and a plain `overflow-x:
   auto` container gives NO signal that content continues — it just looks like a
   cut-off table. Two fixes, both needed:

   1. Break out well past the prose column, up to 84rem, so most viewports show
      every column without scrolling at all.
   2. Where it still overflows, show a real scroll shadow. The layered-gradient
      technique does this with no JS: the `local` layers scroll WITH the content
      and mask the shadow when you reach an edge, while the `scroll` layers stay
      pinned — so a shadow appears on exactly the side that has more content and
      disappears when there is none. Self-correcting, unlike a static fade. */
.table-wrap--wide {
  --break: calc((min(84rem, 100vw - (2 * var(--column-padding))) - var(--column-max-doc)) / 2);
  width: calc(100% + (2 * max(0px, var(--break))));
  margin-left: calc(-1 * max(0px, var(--break)));
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;

  background-image:
    linear-gradient(to right, var(--bg-root), transparent),
    linear-gradient(to left, var(--bg-root), transparent),
    linear-gradient(to right, var(--border-hover), transparent),
    linear-gradient(to left, var(--border-hover), transparent);
  background-position: 0 0, 100% 0, 0 0, 100% 0;
  background-repeat: no-repeat;
  background-size: 44px 100%, 44px 100%, 12px 100%, 12px 100%;
  background-attachment: local, local, scroll, scroll;
}

/* Sticky first column: the partner name is the row's identity, so it must stay
   readable while the numbers scroll under it. */
.partners tbody .p-name,
.partners thead th:first-child {
  position: sticky;
  left: 0;
  background: var(--bg-root);
  z-index: 1;
}

.scroll-hint {
  display: none;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-ghost);
  margin: 0 0 var(--space-2);
}

/* Shown only where the table cannot fit — an instruction that is wrong most of
   the time trains people to ignore it. */
@media (max-width: 60rem) {
  .scroll-hint { display: block; }
}

/* ---------- Number inputs in the partner table ----------
   `width: 7ch` looked sufficient for "18000" and was not: a native number input
   reserves ~18px for spinner arrows INSIDE the content box, so a 7ch field
   rendered about three characters and silently truncated every value on screen.
   The stored number was always correct — it just displayed as "18" — which is
   the worst kind of wrong on a page whose job is showing someone their numbers.

   Spinners are removed rather than accommodated: stepping to 18000 in 100s is
   not a real interaction, and reclaiming the width is what makes the value
   readable. Keyboard up/down still works. */
.partners .calc-mini { width: 9ch; text-align: right; }

/* No spinners on ANY number input here. They eat width, they invite an
   accidental step, and stepping to 18000 in increments was never a real
   interaction. Arrow-key stepping is separately blocked in JS, so the control
   and the keyboard now agree. */
.calc-num,
.calc-mini {
  -moz-appearance: textfield;
  appearance: textfield;
}

.calc-num::-webkit-outer-spin-button,
.calc-num::-webkit-inner-spin-button,
.calc-mini::-webkit-outer-spin-button,
.calc-mini::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Every editable figure gets the same accent-glow response on hover and focus.
   Bible §6: a control that gives no feedback reads as broken — and on a page
   whose whole invitation is "change these numbers", the fields need to look
   changeable before they are touched. */
.calc-mini {
  transition: border-color var(--duration-fast) var(--ease-smooth),
              box-shadow var(--duration-normal) var(--ease-smooth),
              color var(--duration-fast) var(--ease-smooth);
}

.calc-num:hover,
.calc-mini:hover {
  border-color: var(--accent-border);
  box-shadow: var(--glow-accent);
}

.calc-num:focus-visible,
.calc-mini:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--glow-accent);
}

@media (prefers-reduced-motion: reduce) {
  .calc-mini { transition: none; }
}

/* ---------- Calculator B (homeowner savings) ---------- */

.widget {
  margin: var(--space-8) 0 var(--space-10);
  padding: var(--space-6);
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
}

/* The live tool and the prompt that teaches you to build one are two different
   kinds of thing on the same page. One box, one border, one job — so the reader
   never has to work out where the demo stops and the instructions start.
   Bible §3: separation by whitespace first, then a border. Both are earned here
   because the two sections are genuinely different in kind, not just in order. */
.widget > :first-child { margin-top: 0; }
.widget > :last-child { margin-bottom: 0; }

/* Inner surfaces step DOWN to the page background instead of stacking another
   card on top of this one — boxes inside boxes read as clutter, not hierarchy. */
.widget .calc-input {
  background: var(--bg-root);
  border-color: var(--border-subtle);
}

.widget .sc-hero {
  background: var(--bg-elevated);
  border-color: var(--border-default);
}

/* The export block belongs to the widget, so it sits inside the box and loses
   its own breakout. */
.widget .prompt {
  width: 100%;
  margin-left: 0;
  background: var(--bg-root);
}

.sc-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-5);
  margin: var(--space-6) 0;
}

.sc-cell { min-width: 0; }

.sc-fig {
  font-family: var(--font-mono);
  font-size: var(--text-lg);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  margin: 0 0 var(--space-1);
}

/* ---------------------------------------------------------------------------
   TIER 1 — the hero.

   One comparison, and from a cold screenshot it has to be the thing a stranger
   names first (bible §1). It gets the page's only display type, the highest
   surface, and the page's ONLY glow — §5 allows exactly one emitting element,
   and this is it.

   The figure the reader actually came for is the RIGHT-hand one: what they would
   pay all in. The old bill is deliberately quieter, because it is the reference
   point rather than the news. */
.sc-hero {
  margin: var(--space-6) 0;
  padding: var(--space-6) var(--space-5);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

.sc-hero-pair {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: start;
  gap: var(--space-4);
}

.sc-side { min-width: 0; }

.sc-big {
  font-family: var(--font-mono);
  font-size: var(--text-hero);
  line-height: var(--leading-tight);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  margin: var(--space-2) 0 var(--space-2);
}

.sc-big--old { color: var(--text-secondary); }

.sc-big--new {
  color: var(--accent);
  text-shadow: var(--glow-accent);
}

.sc-side-note {
  font-size: var(--text-xs);
  color: var(--text-muted);
  line-height: var(--leading-normal);
  margin: 0;
}

.sc-arrow {
  font-size: var(--text-xl);
  color: var(--text-ghost);
  align-self: center;
  padding-top: var(--space-4);
}

/* The verdict states the uncomfortable case in the same voice as the
   comfortable one — see verdict() in savings-calc.js. It is the sentence that
   decides whether the page is honest, so it is not shrunk into a footnote. */
.sc-verdict {
  margin: var(--space-5) 0 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border-subtle);
  font-size: var(--text-base);
  color: var(--text-secondary);
  line-height: var(--leading-relaxed);
}

.sc-hero--up .sc-big--new { color: var(--accent-strong); }

/* ---------------------------------------------------------------------------
   TIER 2 — the crossover chart.

   Two bars can only describe one year. The cumulative pair plus the year they
   cross is the object that survives follow-up questions, so it sits directly
   under the hero and nothing else on the page is a filled area. */
.sc-figure {
  margin: var(--space-6) 0;
  padding: var(--space-5);
  background: var(--bg-root);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

.sc-figcap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

.sc-cross-note {
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  color: var(--accent);
}

.sc-chart svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

/* The gap after the crossing is the reader's money — the only fill on the page,
   and the reason the chart is here at all. */
.sc-gap {
  fill: var(--accent);
  opacity: 0.16;
}

.sc-line {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* One hue, two lightness steps: the cost that recedes and the one that matters
   (bible §2 — lightness carries hierarchy, hue never moves). The ramp's own
   endpoints are not far enough apart at a 2px stroke — both lines read as the
   same blue — so the receding one also drops opacity. Hierarchy has to survive
   being squinted at. */
.sc-line--nothing { stroke: var(--chart-4); opacity: 0.5; }
.sc-line--solar { stroke: var(--chart-1); }

.sc-cross {
  stroke: var(--border-default);
  stroke-width: 1;
  stroke-dasharray: 3 4;
}

.sc-dot {
  fill: var(--chart-1);
  stroke: var(--bg-root);
  stroke-width: 2;
}

/* Direct labels, so identity never rests on a legend the eye has to travel to. */
.sc-plabel {
  font-family: var(--font-sans);
  font-size: 13px;
  fill: var(--text-muted);
}

.sc-pval {
  font-family: var(--font-mono);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.sc-plabel--solar { fill: var(--text-secondary); }
.sc-pval--nothing { fill: var(--text-muted); }
.sc-pval--solar { fill: var(--chart-1); }

.sc-axis {
  font-family: var(--font-sans);
  font-size: 12px;
  fill: var(--text-ghost);
}

.sc-axis--end { text-anchor: end; }

/* ---------------------------------------------------------------------------
   Home value — hidden until an installer supplies both numbers. */
.sc-value {
  margin: var(--space-6) 0;
  padding: var(--space-5);
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-lg);
}

.sc-value-pair {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3);
  margin: var(--space-2) 0;
}

.sc-value-fig {
  font-family: var(--font-mono);
  font-size: var(--text-xl);
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}

.sc-value-fig--new { color: var(--accent); }
.sc-value-arrow { color: var(--text-ghost); }

/* ---------------------------------------------------------------------------
   Rep mode — the installer's half of the file. */
.sc-rep {
  margin-top: var(--space-6);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-subtle);
}

select.calc-num {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  /* Room for the chevron below, so a long option label stops short of it
     instead of running underneath and looking truncated by accident. */
  padding-right: var(--space-8);
  text-overflow: ellipsis;
}

/* `appearance: none` strips the native arrow, which leaves a control that reads
   as a text box until you click it — silent affordance is the same defect as
   silent interactivity (bible §6). Put it back on the label, in tokens. */
.calc-field:has(select) { position: relative; }

.calc-field:has(select)::after {
  content: '';
  position: absolute;
  right: var(--space-4);
  bottom: 1.15rem;
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid var(--text-muted);
  border-bottom: 2px solid var(--text-muted);
  transform: rotate(45deg);
  pointer-events: none;
  transition: border-color var(--duration-fast) var(--ease-smooth);
}

.calc-field:has(select:hover)::after,
.calc-field:has(select:focus-visible)::after {
  border-right-color: var(--accent);
  border-bottom-color: var(--accent);
}

.calc-label em {
  font-style: normal;
  color: var(--text-ghost);
}

/* Collapsed code block: the export is copyable without spending a screen on it. */
.prompt details { border: 0; margin: 0; }

.prompt details summary {
  padding: var(--space-3) var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-ghost);
  cursor: pointer;
}

.prompt details summary:hover { color: var(--accent); }

@media (max-width: 60rem) {
  .sc-grid { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 480px) {
  .sc-grid { grid-template-columns: 1fr; gap: var(--space-4); }

  /* Stack the hero rather than squeezing three columns: at this width the
     side-by-side pair shrinks the display type below the tier-3 figures and
     inverts the hierarchy it exists to establish. */
  .sc-hero-pair { grid-template-columns: 1fr; gap: var(--space-2); }

  .sc-arrow {
    align-self: start;
    padding-top: 0;
    transform: rotate(90deg);
    transform-origin: left center;
    margin-left: var(--space-2);
  }

  .sc-side--new { margin-top: var(--space-3); }

  /* A 25-year projection needs room to be legible; on a phone the right-hand
     label column is a bigger share of the box, so give it back. */
  .sc-figure { padding: var(--space-4) var(--space-3); }
}

/* `.doc h2` carries a border-top + padding-top as a section divider. Inside the
   boxed widget that renders as a stray rule across the card. `.calc-h` already
   sets border:0 but loses on specificity (0,1,0 vs 0,1,1), so scope it properly
   rather than reaching for !important. */
.doc .calc-h,
.doc .widget h2 {
  border-top: 0;
  padding-top: 0;
}

/* ---------- Scope fixes: .doc descendant rules were winning ----------
   `.doc p` / `.doc h2` are (0,1,1); `.calc-total` / `.calc-h` are (0,1,0), so the
   document defaults silently beat the component. That is why the headline figure
   rendered at body size instead of display size, and why a section divider drew a
   rule across the card. Same root cause both times — scope the component rather
   than escalating with !important. */
.doc .calc-total {
  font-size: var(--text-hero);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  letter-spacing: -0.03em;
  color: var(--text-primary);
  margin: 0;
}

.doc .sc-fig { font-size: var(--text-lg); margin: 0 0 var(--space-1); }
.doc .split-label,
.doc .calc-total-note,
.doc .calc-disclaimer { margin-top: 0; }

/* Same trap, the hero's turn. Every one of these is a <p> inside .doc, so each
   needs the extra class to outrank the prose defaults — losing here collapses
   the display figure to body size and inverts the whole hierarchy. */
.doc .sc-big {
  font-size: var(--text-hero);
  line-height: var(--leading-tight);
  letter-spacing: -0.02em;
  margin: var(--space-2) 0;
}

.doc .sc-big--old { color: var(--text-secondary); }
.doc .sc-big--new { color: var(--accent); }
.doc .sc-hero--up .sc-big--new { color: var(--accent-strong); }

.doc .sc-side-note {
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  color: var(--text-muted);
  margin: 0;
}

.doc .sc-verdict {
  font-size: var(--text-base);
  color: var(--text-secondary);
  margin: var(--space-5) 0 0;
}

/* ---------- Boxed sections ---------- */

.card {
  margin: var(--space-6) 0;
  padding: var(--space-6);
  background: var(--bg-surface);
  border: 1px solid var(--border-default);
  border-radius: var(--radius-lg);
}

.card > :first-child { margin-top: 0; }
.card > :last-child { margin-bottom: 0; }
.card .calc-input { background: var(--bg-root); border-color: var(--border-subtle); }

/* The result is the page's one primary. It gets its own card, the accent hue and
   the display size — everything else on the page is supporting (bible §1). */
.card--result {
  background: var(--bg-elevated);
  border-color: var(--accent-border);
}

.card--result .calc-total { color: var(--accent); }

.result-primary { margin-bottom: var(--space-6); }

.result-secondary {
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-subtle);
}

.doc .result-secondary .calc-total {
  font-size: var(--text-xl);
  color: var(--text-secondary);
}

/* ---------- Live formula ----------
   Shows the arithmetic with THEIR numbers substituted, updating as they type. A
   static diagram would explain the method; this proves the number in front of
   them, which is what actually answers "where did that come from". */
.formula {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  margin: var(--space-3) 0 var(--space-5);
}

.f-term {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  padding: var(--space-2) var(--space-3);
  background: var(--bg-root);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-sm);
}

.f-val { color: var(--text-primary); font-variant-numeric: tabular-nums; }

.f-key {
  font-size: var(--text-xs);
  color: var(--text-ghost);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}

.f-op { color: var(--text-ghost); padding: 0 var(--space-1); }

.f-term--out {
  background: var(--accent-bg);
  border-color: var(--accent-border);
}

.f-term--out .f-val { color: var(--accent); }

@media (max-width: 480px) {
  .card { padding: var(--space-5); }
  .formula { font-size: var(--text-xs); }
}

/* ---------- Two-direction column groups ----------
   The table carries two different kinds of money in one grid: a fee you collect,
   and a customer you gain. Grouping the columns under a spanning header, with a
   divider between the groups, is what makes the two-way street structural rather
   than something the reader has to infer from column names. */
.dir-row th { border-bottom: 0; padding-bottom: var(--space-1); }

.dir {
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  text-transform: none;
  font-weight: var(--weight-medium);
  white-space: nowrap;
}

.dir--out { color: var(--text-muted); }
.dir--in { color: var(--accent); }

/* One divider, on the boundary between the directions. */
.partners th.g-in:first-of-type,
.partners td.g-in:first-of-type,
.partners .dir--in { border-left: 1px solid var(--border-default); }

.partners .g-in { background: var(--accent-bg); }

.partners td.g-out,
.partners th.g-out { color: var(--text-secondary); }

/* ---------- Assumption groups ----------
   The assumptions panel grew from four fields to three distinct subjects, and an
   undifferentiated stack of eight inputs reads as a settings dump. Grouping is by
   whitespace and a label, not another box (bible §3): the panel is already inside
   the widget card, and a third nested border would be depth spent on nothing. */

.sc-group + .sc-group {
  margin-top: var(--space-8);
  padding-top: var(--space-6);
  border-top: 1px solid var(--border-subtle);
}

/* ---------- Checkbox ----------
   A native control, restyled only where it must be: the accent colour, and a tap
   target that clears 44px on a phone. The label is the target too — a checkbox
   you have to hit precisely is a checkbox people get wrong. */

.calc-check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  min-height: var(--tap-min);
  padding: var(--space-2) 0;
  font-size: var(--text-sm);
  color: var(--text-secondary);
  cursor: pointer;
}

.calc-check input[type="checkbox"] {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}

.calc-check:hover { color: var(--text-primary); }

.calc-check input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.calc-check strong { color: var(--text-primary); }

/* Sub-label for a control whose wording carries a trap — here, "completed"
   rather than "paid". Ambient layer: present when looked for, quiet otherwise. */
.calc-hint {
  font-size: var(--text-sm);
  color: var(--text-ghost);
  margin: var(--space-2) 0 0;
}

.calc-hint em { font-style: normal; color: var(--text-muted); }

/* The live consequence of the two controls above it. It changes on every input,
   so it sits at reading weight rather than ghost — it is the answer, not a
   footnote. */
.sc-note {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin: var(--space-4) 0 0;
  padding-left: var(--space-4);
  border-left: 2px solid var(--accent-border);
}

/* ---------- Tax form walkthrough ----------
   Steps down to bg-root: it is a reference artifact quoted inside the panel, not
   a peer of the inputs. Recessed rather than elevated, because it is where you
   look AFTER the number convinces you (bible §5 — elevation is priority). */

.taxforms {
  margin-top: var(--space-6);
  padding: var(--space-5);
  background: var(--bg-root);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-md);
}

.taxsteps {
  list-style: none;
  counter-reset: step;
  margin: var(--space-4) 0 0;
  padding: 0;
}

.taxsteps li {
  display: grid;
  grid-template-columns: 12rem 1fr auto;
  align-items: baseline;
  gap: var(--space-3);
  padding: var(--space-3) 0;
  margin: 0;
  border-bottom: 1px solid var(--border-subtle);
}

.taxsteps li:last-child { border-bottom: 0; padding-bottom: 0; }

.ts-ref {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.ts-what { font-size: var(--text-sm); color: var(--text-secondary); }

.ts-val {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

/* Line 15 is the only figure on this list the taxpayer actually receives. It is
   the one thing here that earns the identity hue. */
.ts-val--out { color: var(--accent); }

@media (max-width: 480px) {
  .taxsteps li {
    grid-template-columns: 1fr auto;
    row-gap: var(--space-1);
  }
  .ts-ref { grid-column: 1 / -1; }
  .taxforms { padding: var(--space-4); }
}

/* ---------- Scope fixes, second round ----------
   Same root cause as the block above, and the reason it is worth restating: the
   widget ships TWICE — once inside `.doc` on our page, once as a standalone
   export with no `.doc` at all. A component that loses to `.doc p` therefore
   renders one way here and another way on the installer's site, which is exactly
   the drift generating the export from live files was meant to make impossible.
   Anything typographic added to this widget needs its `.doc` twin.

   `.split-label` is included even though it predates this change: it was already
   losing font-size, colour and margin to `.doc p`, and the tax-credit block adds
   two more instances of it. */

.doc .split-label {
  font-size: var(--text-xs);
  line-height: var(--leading-normal);
  color: var(--text-ghost);
  margin: 0 0 var(--space-2);
}

.doc .calc-hint {
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--text-ghost);
  margin: var(--space-2) 0 0;
}

.doc .sc-note {
  font-size: var(--text-sm);
  color: var(--text-secondary);
  margin: var(--space-4) 0 0;
}

.doc .taxsteps {
  margin: var(--space-4) 0 0;
  padding-left: 0;
}

.doc .taxsteps li {
  font-size: var(--text-sm);
  margin: 0;
}

.doc .ts-what { color: var(--text-secondary); }
.doc .ts-val { color: var(--text-primary); }
.doc .ts-val--out { color: var(--accent); }

/* A select cannot ellipsize its closed-state text in every engine, so at phone
   width it simply clipped the longer option. Dropping to body size fits both
   ownership labels at 320px without touching the number fields, which are the
   one place the larger mono size is actually doing work. */
@media (max-width: 480px) {
  select.calc-num { font-size: var(--text-base); }
}

/* ---------- `hidden` must actually hide ----------
   The UA sheet's `[hidden] { display: none }` is a bare attribute selector, so
   ANY class that sets `display` outranks it — `.field-row--split { display: grid }`
   did exactly that, leaving the credit-rate and tax fields on screen for a
   lease/PPA even though the DOM said hidden. The element was gone from the
   accessibility tree and still visible, which is the worst of both.

   Scoped to the widget and winning on specificity rather than `!important`, so
   any control this calculator hides in future is hidden for real. */
.widget [hidden] { display: none; }

/* ---------- Wide card: the CARD breaks out, not its contents ----------
   The table was breaking out past its own card, so the card's left and right
   borders drew straight through the rows. A container cannot contain something
   wider than itself — so the card takes the breakout and the table sits inside
   it at 100%. */
.card--wide {
  --break: calc((min(84rem, 100vw - (2 * var(--column-padding))) - var(--column-max-doc)) / 2);
  width: calc(100% + (2 * max(0px, var(--break))));
  margin-left: calc(-1 * max(0px, var(--break)));
}

.card .table-wrap--wide {
  width: 100%;
  margin-left: 0;
  background-image: none;   /* the card edge is the boundary now */
}

/* Sticky column sits on the card surface, not the page. */
.card .partners tbody .p-name,
.card .partners thead th:first-child { background: var(--bg-surface); }

/* ---------- Two directions, equal weight, different tint ----------
   These are the same KIND of money arriving by different routes, so ranking one
   above the other by size misrepresents the model. Identical type scale and
   spacing; the only difference is the surface tint, which carries "different
   version of the same thing" without implying "less important".
   Bible §2: one identity hue — the tint is a lightness/chroma step of it, not a
   second hue. */
.dirs {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
  margin: var(--space-5) 0 0;
}

.dir-card {
  padding: var(--space-5);
  border-radius: var(--radius-md);
  border: 1px solid var(--border-subtle);
}

.dir-card--out { background: var(--bg-elevated); }

.dir-card--in {
  background: var(--accent-bg);
  border-color: var(--accent-border);
}

/* Same size for both — the tint does the distinguishing. */
.doc .dir-card .calc-total {
  font-size: var(--text-xl);
  color: var(--text-primary);
}

.dir-card .split-label { color: var(--text-muted); }
.dir-card--in .split-label { color: var(--accent); }

/* Table groups reuse exactly the same two tints, so the header and the columns
   below it are recognisably the same pair. */
.partners .g-out { background: var(--bg-elevated); }
.partners .g-in { background: var(--accent-bg); }
.dir--out { color: var(--text-muted); }

@media (max-width: 720px) {
  .dirs { grid-template-columns: 1fr; }
}

/* The bridge column is context, not a result — dimmer than the figure it explains. */
.p-val--dim { color: var(--text-muted); font-size: var(--text-xs); }
