/* ========================================================================
   DEPLOY PATH: /css/PvS_style.5d4e90fd.css
   Tepuy Solutions — Property vs Shares calculator — complete styles (dark/light theme)
   Version: 2026-03-31 (headers added)
   Notes: Self-contained. Only load on property_vs_shares.html.
   ======================================================================== */

/* DM Serif Display removed from this request (2026-09). It was fetched on
   every load of this page and used by ZERO selectors: the only other mention
   in the file is the body-rule comment further down, which claimed it was
   "handled by explicit overrides below" — there were none. Re-proved before
   removing: `grep -rn "DM Serif"` over every file in the repo returns hits
   only in css/dashboard.css (a stylesheet this page does not load) and in
   comments/docs. DM Sans and DM Mono are DELIBERATELY KEPT and must not be
   trimmed the same way — both have live consumers on this page: DM Sans in
   js/app1.js and js/share-mode.js (inline style strings), DM Mono in this
   file, css/calculators.css, js/signin-gate.js and the page markup. */
@import url('https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=DM+Sans:wght@300;400;500;600&family=Inter+Tight:wght@400;600;800&display=swap');

/* ── THEME (palette redesign 2026-08) ────────────────────────
   Was a dark-by-default theme with a data-theme="light" toggle
   variant; the toggle and its dark base are removed entirely (no page
   keeps a dark surface any longer, per the site-wide sweep). What was
   the light-theme token block is now the only block, values unchanged
   from what already shipped and was WCAG-AA-verified as this page's
   light mode. --bg-base is repointed to the site's --bone (was a
   self-contained cool-grey #f4f5f8, unrelated to the rest of the site's
   palette); everything else keeps its existing, already-tuned value.
   Retirement-parity pass (2026-08): repointed again, this time to --bg
   (#f7fbfc) — retirement.html's own main-content background (tepuy.css
   "body { background: var(--bg) }"), replacing the --bone cream/beige
   tint so PvS's page background literally matches the accepted
   reference template instead of carrying its own accent. */
:root {
  --bg-base:        var(--bg, #f7fbfc);
  --bg-input:       #f7f8fb;
  /* MOVED to css/simulators.css's shared block (2026-09). It was kept here
     at #505870 only because the shared value was #9aada6 and would have
     failed AA on this page. The shared value is now #55685F, which clears it
     — 5.95:1 on white against #505870's 7.07:1 — so the last of PvS's
     cool slate-blue text ramp goes with it and all five calculators read the
     same sage. */

  /* MOVED to css/simulators.css's SHARED CALCULATOR TOKEN BRIDGE (2026-09):
     --bg-surface, --bg-raised, --bg-hover, --border, --text-primary,
     --text-secondary.

     Why: css/calculators.css's shared rules read these generic names, and
     this file gave them a cool slate-blue ramp (--text-secondary #2c3248,
     --bg-raised #f0f1f5) while retirement.css gave
     the same names a sage-green one. The same byte-identical shared rule
     therefore rendered a different colour per page — .info-tip-popup
     computed rgb(240,241,245) here and rgb(247,250,248) on Retirement, from
     --bg-raised alone. simulators.css is the only shared stylesheet all five
     calculators load, so the definition lives there now.

     Do NOT re-add them here. This file loads AFTER simulators.css, so any
     redeclaration silently wins and re-forks the ramp.

     --bg-input and --border-strong stay: neither is referenced by any shared
     stylesheet, and --border-strong is this page's WCAG 1.4.11 boundary
     colour with its own measured justification below. */
  /* Structural boundary color — for .section/input/select borders
     specifically, the component-boundary cases WCAG 1.4.11 (non-text
     contrast, 3:1) actually applies to. Same blue-gray hue family as
     --border, just with presence: 3.40:1 on white, 3.20:1 against
     --bg-input (used on the toggle track). Design audit, 2026-08. */
  --border-strong:  #828ba3;
  /* --border-focus stays with the gold/clay accent family below — it is
     var(--clay), not a neutral. */
  --border-focus:   var(--clay, #b8922e);
  --shadow-sm:      0 1px 4px rgba(0,0,0,.08);
  --shadow-md:      0 4px 20px rgba(0,0,0,.10);
  --shadow-lg:      0 8px 40px rgba(0,0,0,.12);
  --shadow-gold:    0 0 24px rgba(184,146,46,.15);

  /* Was PvS's own amber/gold accent (#c9a84c), independent of the rest
     of the site. Remapped to --clay — the same "one accent, used
     sparingly" role --clay already plays everywhere else, and the same
     move for_professionals.html's rebrand made for its own --pro-gold.
     --gold-light/-dim keep the existing lighter/darker relationship,
     recomputed from --clay instead of the old literal amber. */
  --gold:       var(--clay, #BE6A3E);
  --gold-on:    #0E1512;   /* 4.69:1 on #BE6A3E; white would be only 3.95:1 */
  --gold-light: color-mix(in srgb, var(--clay, #BE6A3E) 70%, white);
  --gold-dim:   color-mix(in srgb, var(--clay, #BE6A3E) 70%, black);
  /* AA-safe darkened companion for --gold used as *text* (the raw
     --gold hex doesn't clear 4.5:1 on white), applied wherever "gold"
     text appeared. (The --dsc-teal-text this used to cite as the same
     pattern went with the Decision Summary Card.) */
  /* Was 85% clay: the comment above says it was meant to clear 4.5:1 on
     white, but measured from computed styles it renders 4.43:1 — just under.
     70% clears it with margin (6.97:1 by construction) and still reads clay. */
  --gold-text:  color-mix(in srgb, var(--clay, #BE6A3E) 70%, black);

  /* Property = clay, shares = moss — the SAME pairing the KPI cards use, so
     the page cannot tell a reader "property is clay" above the fold and
     "property is blue" below it. Was #4e8ef7 / #4ecb71, neither of which was
     in the token system; the green measured 2.08:1 on white and was failing
     axe on every element it touched.

     Two weights, because the two thresholds are different. WCAG wants 4.5:1
     for text and 3:1 for graphical objects, and raw clay clears the second
     but not the first (3.32:1 on white). So --property is the darkened text
     weight and --chart-property is the mark weight. Moss clears both at
     4.95:1 and needs only one value; --chart-shares exists so the JS reads a
     matched pair of names rather than two differently-shaped ones.

     --chart-* deliberately resolve to a plain hex: js/app1.js reads them with
     getComputedStyle to colour the Chart.js datasets, and a computed custom
     property comes back with var() substituted but color-mix() NOT evaluated.
     Verified in the browser: --gold reads back "#C97A3A" while --gold-text
     reads back the literal "color-mix(in srgb, #C97A3A 70%, black)", which
     Chart.js cannot parse.

     --property-dim / --shares-dim were removed with these: a repo-wide sweep
     found zero uses of either. */
  --property:       var(--gold-text);
  /* Raw moss is 4.95:1 on white, which clears 4.5:1 — but only just, and
     .section-header-shares paints its text on an 8% moss wash rather than on
     white, which measured 4.47:1. Just under. So shares gets the same
     text/mark split property already has: darkened for text (5.83:1 on white,
     5.27:1 on its own wash), raw moss for marks. --chart-shares below stays
     exactly --moss, so the chart series and the KPI card's shares figure
     remain the same colour as the lead bar's shares segment. */
  --shares:         color-mix(in srgb, var(--moss, #4C7A5B) 90%, black);
  --chart-property: var(--clay, #C97A3A);
  --chart-shares:   var(--moss, #4C7A5B);
  /* The cashflow chart's negative bars. NOT the shares colour — that series is
     the property's own cashflow and the second colour there encodes the SIGN.
     It has to sit beside clay, and the old #e05555 did not: measured 1.13:1
     against clay, i.e. near-indistinguishable, where the old blue it used to
     sit beside was at least a different hue family. This is the deep red
     css/tepuy.css already uses for .tsd-btn--danger:hover, which separates
     from clay by lightness rather than hue — 2.64:1 against clay and 8.77:1
     on white, against #e05555's 3.75:1. Colour is not the cue that carries
     this distinction in any case: a negative bar leaves the zero axis
     downward. */
  --chart-negative: #832f22;
  --moss-light:     color-mix(in srgb, var(--moss, #4C7A5B) 55%, white);

  /* Retirement-parity pass (2026-08): --success was declared three times
     in this same :root block (this one, plus #2d8a4e near the top and
     #4ecb71 above — both now dead code, silently overridden by source
     order; only ever mattered because var(--success) has exactly one
     consumer, .td-pos, and all three greens were close enough in hue
     that the bug was invisible). Collapsed to one declaration, ported to
     retirement.html's own --success (tepuy.css, #28a745). --warning and
     --danger also ported to retirement's exact values (#ffaf1a /
     #e03434, tepuy.css) — --danger as text on white actually improves
     (3.75:1 -> 4.46:1, was already borderline-failing AA normal-text
     contrast). --warning as raw text (.section-header-exit/.td-exit/
     .td-exit-highlight) was already failing WCAG AA before this change
     (old #f5a623: ~2.0:1) and remains failing after (new #ffaf1a:
     ~1.8:1) — porting the token doesn't fix or meaningfully worsen a
     pre-existing text-contrast bug in those specific consumers; flagged
     as a follow-up, not fixed here (out of scope for a token port). */
  --success: #28a745;
  --warning: #ffaf1a;
  --danger:  #e03434;

  --radius-sm: 4px;
  --radius-md: 8px;
  --radius-lg: 14px;
  --radius-xl: 20px;
  --transition: all .18s cubic-bezier(.4,0,.2,1);
}

/* ── RESET ───────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* html{font-size} moved to css/calculators.css (2026-08 consolidation
   audit) — this used to declare 15px here, later silently overridden to
   15.5px by a rule further down this file, neither matching
   retirement.html's un-overridden 16px default. Every rem-sized element
   on this page was rendering ~3-6% smaller than its retirement.html
   equivalent as a result. Fixed once already by pinning this file's own
   value to 16px; fixed properly now by making calculators.css (loaded
   after this file on both pages) the one declaration both pages actually
   share, instead of two pages independently agreeing to the same number.
   scroll-behavior stays here — genuinely page-specific, not part of the
   shared type scale. */
html { scroll-behavior: smooth; }
/* Retirement-parity pass (2026-08): body was self-importing DM Sans as
   this page's own base font, independent of the rest of the rebranded
   site — the root cause of KPI labels/values-surrounding text, buttons,
   and headline accents all reading in a different typeface than
   retirement.html (which inherits 'Inter Tight' from tepuy.css's body
   rule, unopposed). Repointed to the exact same stack tepuy.css uses,
   so every element on this page that relied on inheriting body's font
   (not just .kpi-label, but any other unstyled text) now matches
   retirement.html without needing a per-selector override — the same
   thing retirement.html itself does. DM Mono (numeric/tabular figures)
   is unaffected by this change. (This comment also used to name DM Serif
   Display as "headline accents, handled by explicit overrides below". There
   were no such overrides — zero selectors in this file ever referenced it —
   so the family is no longer requested; see the @import at the top.) */
body {
  font-family: 'Inter Tight', system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial,
               "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  background: var(--bg-base);
  color: var(--text-primary);
  min-height: 100vh;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  transition: background .25s, color .25s;
  /* CHANGED (2026-08, navbar-fixed fix) — was padding-top: 0, cancelling
     tepuy.css's own body{padding-top:64px} compensation for its
     position:fixed navbar. That cancellation was only correct while
     PvS's navbar was (incorrectly) position:sticky, in-flow, reserving
     its own space naturally. Now that the navbar is genuinely
     position:fixed (see EXCEPTION 2 and the removed header:not(.page-head)
     rule above), this MUST reserve that space itself or page content
     renders underneath the fixed bar. 60px (not tepuy.css's 64px) to
     match EXCEPTION 1's navbar height:60px and every other 60px-based
     measurement already hardcoded through this file (.sidebar's
     top/height, etc.) — see EXCEPTION 1's own comment for the full list. */
  padding-top: 60px;
}
/* ── SCROLLBAR ───────────────────────────────────────────── */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: var(--bg-base); }
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 99px; }
::-webkit-scrollbar-thumb:hover { background: var(--gold-dim); }

/* ── LAYOUT ──────────────────────────────────────────────── */
/* PvS is now on the shared calculator shell: <body class="calc">,
   .main-layout, aside.calc-aside.aside--bare, .sidebar-panel,
   .sidebar-scroll — the same five names Mortgage, Offset vs Shares, LMI and
   Retirement use. What used to live here (.app-shell's grid,
   .main-content's `grid-template-columns: 360px 1fr`, and a private
   container-query scaffold) was a parallel copy of tepuy.css sections 3 and
   14; it is deleted rather than renamed.
   .app-shell survives as a plain full-height wrapper only — it is no longer a
   layout fork, and it is kept solely because removing the element would
   re-indent 1,300 lines of markup for no rendered change. */
.app-shell { min-height: 100vh; }

/* THE CONTAINER NAMES ARE THE WHOLE RISK IN THIS MIGRATION, so they are
   spelled out rather than inherited.
   tepuy.css declares `body.calc { container-name: calc-layout }`. That is
   (0,1,1); the `body { container-name: pvs-layout }` this file used to carry
   is (0,0,1), so adding class="calc" would have let tepuy.css win outright
   and every `@container pvs-layout` query in this file — five tiers at 1200,
   900, 800, 768 and 480px — would have stopped matching, silently and with no
   error anywhere. A container can hold more than one name, so it holds both:
   the shared tier queries reach PvS for the first time AND its own five keep
   working.
   Same trap one level down on <main>: tepuy.css puts `container-name:
   calc-main` on `body.calc .main-layout > main`, which is this element.
   pvs-sidebar is NOT carried over — it was declared here and queried nowhere
   (grepped: zero `@container pvs-sidebar` rules in the repo). tepuy.css's own
   calc-sidebar, on .sidebar-panel, replaces it and is actually used. */
body.calc {
  container-type: inline-size;
  container-name: calc-layout pvs-layout;
}
body.calc .main-layout > main {
  container-type: inline-size;
  container-name: calc-main pvs-main;
}

/* ── WHAT THE SHARED SHELL BRINGS THAT PvS DOES NOT TAKE ─────────────────
   Adopting body.calc/.main-layout/.calc-aside also adopts tepuy.css's
   spacing, and that is a visible redesign of the flagship rather than the
   structural convergence this change is for. Each property below was
   MEASURED as a difference (Chromium, eleven widths from 1440 down to 320,
   before vs after) and is restored to what PvS rendered before, so the
   migration is provably a no-op on screen.

   Everything NOT listed here is allowed to converge. In particular the rail
   and panel background move from PvS's --bg-raised (#f7faf8) to the shared
   --sb-bg (#f4f8f6): three units per channel, indistinguishable, and
   css/simulators.css declares it !important precisely so all five agree.

   Adopting the shared spacing as well is a separate, deliberate decision —
   it costs a phone 57px of sidebar width (measured at 390px: .sidebar-scroll
   357px -> 300px) and it is not this change's to make. Recorded in
   docs/OPEN-ITEMS.md as needing a design call. */

/* .main-layout carries `padding: 0 1rem 2rem`; PvS's .main-content had none,
   and the page is designed edge-to-edge. Unconditional, so it also beats the
   stacked tier's `0 0.75rem 1.25rem` on source order. */
body.calc .main-layout { padding: 0; }

/* The shared panel is a rounded bordered card floating in the rail. PvS's is
   a flat rail that meets the page edge — the same "genuine divergence" the
   other three calculators keep in their own -polish.css files (see
   css/simulators.css's note on the flush-right-edge treatment, deliberately
   NOT shared). PvS has no -polish.css, so it lives here. */
body.calc .calc-aside .sidebar-panel {
  border: 0;
  border-left: 0;
  border-radius: 0;
}

/* main: PvS's own 20px, and no divider rule — the rail already has its own
   border-right, so tepuy's border-left would draw a second line beside it. */
body.calc .main-layout > main {
  padding: 20px;
  border-left: 0;
}

@container calc-layout (max-width: 799.98px) {
  /* The shared stacked tier insets the panel and releases the scroller.
     PvS's own 900px tier already stacks; these two lines are only about the
     gutters it does not want. overflow-x stays hidden for the reason the
     .sidebar-scroll rule below gives — a wide child must scroll inside it,
     not widen the page. */
  body.calc .calc-aside .sidebar-panel { margin: 0; height: 100%; }
  body.calc .calc-aside .sidebar-scroll { overflow-x: hidden; overflow-y: auto; }
  body.calc .main-layout > main > #page-head-placeholder { padding: 0; }

  /* The shared tier flattens <main> and then sets `padding: 0 0.25rem` on
     every child it flattened. That selector carries :not(#page-head-
     placeholder), so the id inside :not() counts and it resolves to (1,2,1) —
     high enough to beat each child's OWN padding, which is what actually
     happened here. Measured at 799, 414, 390 and 320px, every flattened child
     collapsed to `0px 4px`:

         #pvs_shared_banner   10px 16px          ->  0px 4px
         .edu-section         24px 32px 32px     ->  0px 4px
         #empty_state / #results_content / #calcComplianceNote   0px -> 0px 4px

     The .edu-section restoration rule this comment used to describe is gone
     (2026-09): the section converted from .edu-section to .calc-explainer,
     which — matching Mortgage/LMI/Offset's own .calc-explainer — carries no
     padding/background/border of its own, so there is nothing left to
     restore at this breakpoint. The other two restorations are unrelated to
     that conversion and still apply. The :not(#page-head-placeholder) they
     carry purely out-specifies the reset above them — without it the
     reset's borrowed id wins and they never apply. */
  body.calc .main-layout > .results-panel > :not(#page-head-placeholder) { padding: 0; }
  body.calc .main-layout > .results-panel > #pvs_shared_banner:not(#page-head-placeholder) { padding: 10px 16px; }
}

/* ── HEADER ──────────────────────────────────────────────── */
/* REMOVED (2026-08, navbar-fixed fix) — this used to hold a full parallel
   header treatment (height/border/padding/shadow AND, critically,
   `position: sticky; top: 0`). The comment above claimed ".navbar's
   higher-specificity rule should already win on paper" — that assumption
   was wrong. `header:not(.page-head)` is an element selector plus a
   :not() whose argument's specificity counts, so it resolves to (0,1,1) —
   HIGHER than the bare `.navbar` class selector's (0,1,0), in tepuy.css
   AND in this file's own now-also-removed ".navbar { position: sticky }"
   override below (EXCEPTION 2). This rule was silently winning the
   position property on every load, and unlike ".navbar", <header>'s
   *containing block* for sticky purposes is just #navbar-placeholder — a
   box exactly as tall as the header itself, with zero extra room for
   "sticky" to ever hold: confirmed live (Playwright scroll test) that the
   navbar scrolled off-screen immediately, in exact lockstep with
   scrollY, on every page load. tepuy.css's ".navbar" is `position: fixed`
   for exactly this reason — fixed has no containing-block-height
   dependency at all. See EXCEPTION 2 below: PvS now uses that same fixed
   navbar unopposed, matching Mortgage/Offset vs Shares/Retirement. This
   rule's other properties (height/border/padding/shadow/flex) are already
   covered by tepuy.css's own ".navbar"/".navbar-inner" (see the "TEPUY
   NAVBAR" section further down) plus EXCEPTION 1's height:60px override,
   so nothing here needs to be kept. */

.logo {
  font-family: 'Inter Tight', sans-serif;
  font-weight: 600;
  font-size: 1.2rem;
  color: var(--gold);
  white-space: nowrap;
}
.logo span {
  color: var(--text-muted);
  font-size: .78rem;
  font-family: 'Inter Tight', sans-serif;
  font-weight: 400;
  margin-left: 10px;
  letter-spacing: .01em;
}

/* ── PAGE HEAD ───────────────────────────────────────────────
   PvS's own copy of the shared page-head component now filled in via
   js/page-head-include.js (same mechanism as #navbar-placeholder above)
   — same markup, same rule values as .page-head/h1/.sub/::after in
   css/tepuy.css (the pattern shared by the other calculators): one
   title, one subtitle, a full-width divider, stacked paragraph-style on
   wide screens, side-by-side two columns below 800px. tepuy.css's own
   copy points its breakpoint at @container calc-layout rather than the
   .main-layout > main element to dodge a display:contents bug — not
   relevant here since pvs-layout (declared on <body>) never has that
   conflict, but the values themselves are copied 1:1 either way. */
.page-head {
  /* No padding of its own, matching tepuy.css's canonical .page-head —
     #page-head-placeholder is now .results-panel's first child (moved
     2026-08, was a direct child of .app-shell with no padded ancestor),
     so .results-panel's own padding already carries the page's edge
     spacing and this only needs to add its bottom margin. */
  margin-bottom: 1.25rem;
}
.page-head h1 {
  font-size: clamp(1.35rem, 2.5vw, 1.75rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: #0f1c16;
  line-height: 1.2;
}
.page-head .sub {
  font-size: 0.925rem;
  color: #4a655a;
  margin: 0.35rem 0 0;
  line-height: 1.5;
}
.page-head::after {
  content: "";
  display: block;
  height: 1px;
  background: var(--border);
  margin-top: 0.75rem;
}

@container pvs-layout (max-width: 800px) {
  .page-head {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
    align-items: start;
  }
  .page-head::after {
    grid-column: 1 / -1;
  }
}

/* ── THEME TOGGLE ────────────────────────────────────────── */
.theme-toggle {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 99px;
  padding: 5px 12px 5px 8px;
  transition: var(--transition);
  flex-shrink: 0;
}
.theme-toggle:hover { border-color: var(--gold-dim); }
.theme-toggle-icon { font-size: 1rem; line-height: 1; }
.theme-toggle-label {
  font-family: 'Inter Tight', system-ui, -apple-system, sans-serif;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* ── SIDEBAR ─────────────────────────────────────────────── */
/* CANONICAL PATTERN — calculator sticky sidebar. This is the SAME
   mechanism as tepuy.css's `body.calc .calc-aside` (see tepuy.css,
   "14) CALCULATORS — fixed left rail"), which Mortgage/Offset vs
   Shares/Retirement all use unmodified: position: sticky (not fixed —
   fixed would need manual left-edge centering math against
   .main-content's max-width: 1200px/margin: 0 auto, which the grid
   column already gives sticky for free), pinned `height` so the sidebar
   scrolls its own contents via overflow-y once they exceed the viewport,
   released back into normal flow once .main-content's row (driven by
   whichever of .sidebar/.results-panel is taller) runs out — confirmed
   live via Playwright scroll sweep, same release behavior as Mortgage's
   own aside on its own longer page.
   PvS keeps its own class names (.sidebar, not .calc-aside) rather than
   adopting tepuy.css's directly: this file has ~2000 lines of component
   CSS (accordions, KPI cards, chart wraps, etc.) built against .sidebar/
   .results-panel/.app-shell, and renaming the outer shell would mean
   auditing every one of those for accidental collisions with tepuy.css's
   OWN .calc-aside descendant rules (.card, .card-header, .form-row, etc.
   — see tepuy.css section 14) — a large, high-blast-radius rewrite for a
   purely cosmetic class-name win. The VALUES (60px, not tepuy.css's
   var(--stick-top): 80px) are PvS's own — see EXCEPTION 1 in the "TEPUY
   NAVBAR" section below for why 60px is pinned throughout this file.
   A genuinely NEW calculator should use tepuy.css's `.main-layout` +
   `.calc-aside.aside--bare` + `.sidebar-panel` + `.sidebar-scroll`
   directly (the Mortgage/Retirement pattern), not copy this block —
   this comment exists so a future session finds the real canonical
   source instead of re-deriving it from PvS's parallel copy. */
/* THE DEVIATIONS, at body.calc .calc-aside — equal specificity to tepuy.css's
   own rule and later in source order, so these win. css/simulators.css's
   header names this exact hazard: "adopting .calc-aside on the outer shell
   would hand that higher-specificity tepuy.css rule the sticky/top/height
   properties and silently reintroduce the exact disclaimer-bar-overlap bug
   PR #83 fixed." It would have: tepuy.css sets top: var(--stick-top) (80px)
   and height: calc(100vh - var(--stick-top)), against the 60px navbar and the
   extra 60px disclaimer clearance PvS's math is measured for. Both are
   restated below at a specificity that holds. */
body.calc .calc-aside {
  /* FIX (2026-08, sidebar-restructure) — was var(--bg-surface) (white),
     matching the main panel exactly instead of reading as a distinct
     rail. Mortgage's own sidebar (mortgage-polish.css, "SIDEBAR
     SURFACE") uses a flat #f4f8f6 for both .calc-aside and
     .sidebar-panel — var(--bg-raised) (#f0f1f5) is PvS's own existing
     token for the same "barely-tinted, not-quite-white surface" job,
     reused here rather than hardcoding a second near-identical value.
     overflow-y: auto REMOVED — scrolling now lives on .sidebar-scroll
     below instead of the whole aside, so .sidebar-footer (Run
     Comparison + its button rows) can stay pinned outside the scroll
     region instead of scrolling away with the accordion list. */
  background: var(--bg-raised);
  border-right: 1px solid var(--border);
  /* CONFIRMED BUG (2026-08) — was calc(100vh - 60px), filling the
     viewport exactly flush with its bottom edge. #disclaimerFooter is
     position:sticky; bottom:0 (pre-existing, unrelated to this
     restructure) and sits in that exact same spot — before this
     session's sidebar-footer pinning, whatever content fell at the
     tail of .sidebar's own internal scroll only rarely landed there,
     and could be scrolled clear of it regardless; now that
     .sidebar-footer (Run Comparison + Save/Load) is pinned flush with
     .sidebar's own bottom edge, it landed exactly under the disclaimer
     bar with no way to scroll clear — confirmed live, Save/Load
     visually covered and unclickable at both 900px and 1080px viewport
     heights. The extra 60px subtracted here (measured disclaimer bar
     height: 54px at 1440px width, +6px buffer for its text wrapping
     onto an extra line at narrower widths) stops .sidebar short of the
     true viewport bottom, leaving the disclaimer bar its own clear
     strip below the sidebar instead of overlapping it. When the bar is
     dismissed (its own close button) this reads as a bit of extra
     breathing room at the sidebar's bottom, not a visible gap. */
  height: calc(100vh - 60px - 60px);
  position: sticky;
  top: 60px;
}
/* .sidebar-panel is now the flex column that makes the pin possible:
   .sidebar-scroll (flex: 1, its own overflow-y) takes all the space
   .sidebar-footer (flex-shrink: 0) doesn't need, so the footer always
   lands at the bottom of .sidebar's own fixed height — never pushed
   down by how much accordion content happens to be open above it, and
   never scrolled away with it either. Mirrors tepuy.css's canonical
   `body.calc .calc-aside .sidebar-panel { display:flex; flex-direction:
   column }` + `.sidebar-scroll { flex:1 1 auto; min-height:0; overflow-y:
   auto }` mechanism (see the CANONICAL PATTERN comment on .sidebar
   above) under PvS's own class names. */
.sidebar-panel {
  padding: 16px;
  height: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
}
.sidebar-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  /* CONFIRMED COLLISION (2026-08) — tepuy.css has its own bare, unscoped
     `.sidebar-scroll { background: var(--brand) }` (dark Tepuy green,
     written for a DIFFERENT — body.calc — sidebar pattern that never
     applies here since PvS's <body> has no .calc class). PvS loads
     tepuy.css before this file, so equal specificity + later source
     order means PvS's own declarations win where they compete — but
     background wasn't originally declared here, so tepuy's dark-green
     value was the only one in play and silently won. Confirmed live:
     the eyebrow title rendered dark-green-on-dark-green, invisible.
     transparent here lets .sidebar's own var(--bg-raised) show through
     instead, same as intended. */
  background: transparent;
}
.sidebar-footer {
  flex-shrink: 0;
  margin-top: 10px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
/* .pvs-sidebar-title / .pvs-sidebar-sub / .pvs-calc-hint moved to
   css/simulators.css (Step 3, 2026-08-19) — identical values, now shared
   with Mortgage/Offset/LMI's equivalent eyebrow/hint rules via a
   .pvs-* branch on those selectors. */

/* ── ACCORDION ───────────────────────────────────────────── */
/* Design audit, 2026-08: border strengthened to --border-strong (3.4:1 on white, was 1.37:1,
   was 1.37:1) and a soft shadow added — previously relying entirely on
   that near-invisible 1px line for definition, with zero shadow anywhere
   on the accordion.
   Retirement-parity pass (2026-08): radius and shadow re-ported to
   retirement.html's exact "aside .card" values (retirement.css) — 14px
   (--tp-radius-card, was a PvS-specific 10px) and the 2-layer resting
   shadow --tp-shadow-card. Hover previously only changed border-color;
   retirement.html's card hover is a shadow lift instead
   (--tp-shadow-card-hover, with an explicit "transform: none" since its
   own .card:hover elsewhere in retirement.css sets a transform this
   needs to cancel — kept here too for a literal port even though
   nothing in this file currently sets one). */
/* .section/.section-header/.section-icon (+ 8 .icon-* variants)/
   .section-title/.section-chevron/.section-body all removed here — Step 3
   (2026-08-19) sidebar rebuild:
   - .section -> .card, .section-header -> .card-header,
     .section-body -> .card-content (markup renamed in
     property_vs_shares.html), styled via css/simulators.css's shared
     .sidebar .card* branch instead of locally.
   - .section-icon and all 8 .icon-* category-color variants removed
     entirely, no replacement — confirmed in the UI polish audit as
     "removed, not migrated".
   - .section-chevron (text-glyph "▼") removed entirely — the shared
     .card-header::after SVG chevron in simulators.css replaces it, no
     markup element needed.
   - .section-title div replaced with a plain <h4> inside .card-header,
     matching Mortgage/Offset/LMI's markup — this also resolves the
     dashed-connector-line finding from the UI audit: that line was never
     PvS's own design, it was an accidental collision with tepuy.css's
     unrelated blog-heading .section-title::after rule (tepuy.css:2692).
     Renaming away from .section-title removes the collision at the
     source instead of overriding it.
   @keyframes slideDown is now unused (only .section-body's open animation
   referenced it) and removed with it. */

/* ── FORM CONTROLS ───────────────────────────────────────── */
.field { margin-bottom: 14px; }
.field:last-child { margin-bottom: 0; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
/* Two lines reserved for the label, so both cells' inputs start level — see
   the matching `aside .grid-2 > .form-row > label` rule in css/tepuy.css for
   the measurements and for why `align-items: end` is the wrong mechanism
   (these cells carry .hint text below the input, so bottom-aligning the cell
   aligns the hint instead). This page had the most of the defect: 5 of its 12
   two-column rows misaligned, up to 22px. 3.2em is two lines at this file's
   1.6 label line-height. */
.field-row > .field > label {
  min-height: 3.2em;
}

label {
  display: block;
  /* font-family audit (2026-08): inherits body's stack, see .section-title above. */
  font-size: .68rem;
  font-weight: 600;
  color: var(--text-secondary);
  margin-bottom: 4px;
  letter-spacing: .03em;
  text-transform: uppercase;
}
label .hint {
  color: var(--text-muted);
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
  margin-left: 4px;
  font-size: .65rem;
}

.input-wrap { position: relative; display: flex; align-items: center; }
.input-prefix, .input-suffix {
  position: absolute;
  /* Was 'DM Mono', monospace — missed by the Step 3 input font fix above,
     which only targeted input[type="number"]/input[type="text"]/select.
     .input-prefix/.input-suffix are separate <span> elements with their
     own font-family declaration, so they kept rendering DM Mono even
     after the inputs themselves switched to Inter Tight. Confirmed live
     via getComputedStyle across all 34 prefix/suffix spans on the page
     before this fix — every one still resolved to DM Mono. Same explicit
     stack as the input fix, not `font-family: inherit` — inputs/spans
     don't reliably inherit from the page (see the input rule's own note
     above). */
  font-family: 'Inter Tight', system-ui, -apple-system, 'Segoe UI', Roboto,
               Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
  font-size: .72rem;
  color: var(--text-muted);
  pointer-events: none;
  z-index: 1;
}
.input-prefix { left: 9px; }
.input-suffix { right: 9px; }

/* .sidebar .card-content — NOT just a naming nicety. tepuy.css:1684 has a
   generic ".card-content input:not([type=checkbox]):not([type=radio]),
   .card-content select" fallback rule (specificity 0,3,1 — the two :not()
   attribute args each count as a class) for pages using the shared card
   pattern outside body.calc .calc-aside. PvS's inputs started matching it
   for the first time the moment Step 3 renamed .section-body to
   .card-content — before that they were never in a .card-content at all,
   so this collision didn't exist. Unscoped, PvS's own rule below
   (previously 0,1,1) loses that specificity fight, and tepuy.css's
   padding:.5rem silently wins over PvS's own padding — collapsing the
   $-prefix gap into an overlap, and also overriding border-radius/
   border-color/background/font-size/color and adding an unwanted
   margin-top none of that was true font-family-swap fallout. Prefixing
   with .sidebar .card-content (both real, always-present ancestors —
   every input/select on this page lives inside <aside class="sidebar">)
   brings specificity to a tie (0,3,1); PvS_style.css loads last (see the
   <head> comment above the stylesheet links), so the tie resolves in its
   favor. Fixes the collision by not colliding, same approach as the
   dashed-connector fix above — not a font-metrics patch. */
.calc-aside .card-content input[type="number"],
.calc-aside .card-content input[type="text"],
.calc-aside .card-content select {
  width: 100%;
  background: var(--bg-input);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text-primary);
  /* Was 'DM Mono', monospace — UI polish audit finding #8: DM Mono is not
     the site's canonical font (Inter Tight is) and these inputs aren't
     tabular data, the one case DM Mono is meant for.
     Explicit stack, not `font-family: inherit` or just deleting the line —
     confirmed live (getComputedStyle) that form controls (input/select/
     textarea) do NOT inherit font-family from the page by default in
     Chromium's UA stylesheet; removing the declaration entirely computed
     to plain "Arial", not body's stack. Same literal stack body already
     uses (line ~128 above). */
  font-family: 'Inter Tight', system-ui, -apple-system, 'Segoe UI', Roboto,
               Helvetica, Arial, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
  font-size: .78rem;
  padding: 7px 9px;
  margin-top: 0;
  outline: none;
  transition: var(--transition);
  appearance: none;
}
/* The dropdown chevron — the same defect sidebar-polish.css:669 records
   fixing for the other four calculators on 2026-09-05, on the fifth. That
   fix was scoped to `#advModePanel`, which PvS does not use, and PvS does
   not load sidebar-polish.css at all, so its four selects were never in it.

   Two bare `select { background-image: <chevron> }` rules used to sit near
   the bottom of this file, at #5a6070 and #8890a8. NEITHER EVER PAINTED, on
   any release. Measured in Chromium, all four of this page's selects
   computed `background-image: none` — and identically at c1bbb73^, before
   #242 put the page on the shared shell, so this is not shell fallout.
   Chromium's own matched-rule list names two different winners across that
   boundary, each setting the `background:` SHORTHAND, which resets
   background-image:

       before #242   tepuy.css:1709  `.card-content select`            (0,2,1)
       after  #242   tepuy.css:4313  `body.calc .calc-aside
                                      .card-content select`            (0,3,2)

   A bare `select` is (0,0,1) and loses to both. `padding-right` went the
   same way: 9px from `padding: 7px 9px` above, never the 26px a chevron
   needs.

   The rule above ALSO sets `appearance: none`, which a background shorthand
   does NOT reset. So the net effect was four dropdowns on the flagship with
   no indicator of any kind — not a contrast defect, an absent control
   affordance. It is invisible to an axe scan for exactly the reason
   sidebar-polish.css gives: there is no chevron there to measure.

   Specificity (0,3,2) matches tepuy.css:4313 exactly and PvS_style.css loads
   after tepuy.css (see the <head> comment above the stylesheet links), so the
   tie resolves here — no `!important` needed, unlike sidebar-polish.css,
   which is fighting an equally-specific rule in a file that loads after it.

   #55685F is the canonical muted tone from #207, 5.95:1 on the white these
   render on — the same chevron the other four calculators carry. */
body.calc .calc-aside .card-content select {
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%2355685F'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 9px center;
  padding-right: 26px;
}

/* The gold input-focus rule that stood here was DEAD and is removed.
   `body.calc .calc-aside .card-content input:focus` in css/tepuy.css
   (specificity 0-4-2) beat this selector (0-4-1), so none of its three
   declarations ever reached an input or select. Proven by ablation before
   removal: disabling PvS_style.css left the focus ring unchanged, while
   disabling tepuy.css restored the gold — the definition of a rule that
   contributes nothing.

   Its `rgba(201,168,76,.08)` was also the pre-rebrand gold (#c9a84c),
   hardcoded rather than tokenised, and no longer what --gold resolves to
   (#C97A3A). Debris, not a design choice.

   The live green focus treatment on all five calculators comes from
   css/tepuy.css and is unchanged by this removal. NOTE: gold focus is still
   rendered on this page by a DIFFERENT rule below —
   `.input-wrap:has(.input-suffix):focus-within` — which wraps the ~22
   suffix fields and is untouched here. */
.calc-aside .card-content .has-prefix input { padding-left: 20px; }

/* Suffix fields ($-prefix is unaffected, still fixed-width padding-left
   above — "$" is always exactly one character, not the class of bug
   below). A fixed padding-right budget (previously 26px) works for short
   suffixes ("%", "yrs") but silently overlaps for longer ones ("% of
   building value") — pre-existing, reproduces identically on unmodified
   main with the original DM Mono font, so not a font-metrics issue
   either. Rather than pick a bigger fixed number (which just moves the
   same bug to the next long suffix string), the suffix becomes a real
   flex sibling instead of an absolutely-positioned overlay, and the
   input gets flex:1 — the browser reserves exactly the suffix's actual
   rendered width, so there's no px budget to run out of at any length.
   Border/background move from <input> onto the wrap since the input can
   no longer own the whole visual "pill" once the suffix sits inside it
   as flex content rather than overlaid on top.
   :has(.input-suffix) targets by actual content rather than the
   .has-suffix wrap class, which also incidentally fixes strata_fees:
   its wrap carries only .has-prefix despite containing a suffix span,
   so it never matched the old .has-suffix rule and was always overlap-
   prone at the default 9px padding-right. */
.calc-aside .card-content .input-wrap:has(.input-suffix) {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--bg-input);
  padding-right: 9px;
  transition: var(--transition);
}
/* Focus for the suffix "pill". This is the ONLY focus indicator these ~22
   fields have: the rule below strips the inner input's border, background
   and box-shadow, and its :focus rule explicitly zeroes them again, so the
   wrap has to carry it. Deleting this block outright leaves the focused
   state byte-identical to the resting state — measured: border, ring and
   background all unchanged, with outline:none on the input — which is a
   WCAG 2.4.7 failure on every $ / % field. So the gold is replaced, not
   removed.

   What was here:
     border-color: var(--gold);                    -> #C97A3A, the CURRENT clay
     box-shadow: 0 0 0 3px rgba(201,168,76,.08);   -> #c9a84c, PRE-REBRAND
   Only the shadow was stale debris; the border was the live accent token.
   Both go, because the point is to converge on the one focus treatment the
   rest of the site uses.

   These are the same two declarations css/tepuy.css states for
   `body.calc .calc-aside .card-content input:focus` — the rule that governs
   every other input on this page — so a suffix field and a plain field now
   focus from one source of truth rather than two. */
.calc-aside .card-content .input-wrap:has(.input-suffix):focus-within {
  border-color: #1a6b4a;
  background: var(--bg-hover);
  box-shadow: 0 0 0 2px rgba(26,107,74,.15);
}
.calc-aside .card-content .input-wrap:has(.input-suffix) input[type="number"],
.calc-aside .card-content .input-wrap:has(.input-suffix) input[type="text"] {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  background: transparent;
  border-radius: 0;
  padding-right: 6px;
}
.calc-aside .card-content .input-wrap:has(.input-suffix) input:focus {
  border-color: transparent;
  background: transparent;
  box-shadow: none;
}
.calc-aside .card-content .input-wrap .input-suffix {
  position: static;
  flex: 0 0 auto;
  white-space: nowrap;
  padding-left: 4px;
}


/* Range — input[type="range"]/::-webkit-slider-thumb moved to
   css/simulators.css (Step 3, 2026-08-19): now shared via a .sidebar
   branch on the same rule Mortgage/Offset/LMI/Retirement would use if
   any of them had a slider. Colors there are the shared brand green, not
   this file's --gold — a deliberate, visible change (see simulators.css's
   §6 comment). .range-wrap stays here (layout wrapper, still tied to this
   page's markup). .range-val's font-family dropped for the same reason
   as the input font-family above — DM Mono isn't tabular data here
   either, just a single slider readout number. */
.range-wrap { display: flex; align-items: center; gap: 8px; }
.range-val { font-size: .72rem; color: var(--gold); min-width: 36px; text-align: right; }

/* Toggle switch (row/label/slider) moved to css/calculators.css — 2026-08
   Stage 2. Its tepuy.css class-name-collision fix (label.toggle vs bare
   .toggle) traveled with it unchanged; see calculators.css for the note. */

/* Radio group */
.radio-group {
  display: flex; gap: 3px;
  background: var(--bg-input);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 3px;
}
.radio-group label {
  flex: 1; text-align: center;
  padding: 4px 5px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  font-size: .66rem; font-weight: 600;
  color: var(--text-muted);
  letter-spacing: .03em; text-transform: uppercase;
  margin: 0; transition: var(--transition);
}
.radio-group input[type="radio"] { display: none; }
.radio-group input[type="radio"]:checked + label {
  background: var(--bg-raised); color: var(--gold);
  box-shadow: var(--shadow-sm);
}

/* ── CALCULATE BUTTON ────────────────────────────────────── */
/* .btn-calculate/.btn-secondary/.btn-row (css/calculators.css, 2026-08
   Stage 2) are no longer used by the sidebar footer as of the Step 3
   sidebar rebuild (2026-08-19) — the primary button is now #runBtn
   (class="btn btn-primary"), styled by css/simulators.css's shared
   .sidebar .sidebar-footer #runBtn rule, same mechanism Mortgage/Offset/
   LMI use. calculators.css's .btn-calculate/.btn-secondary/.btn-row
   classes are left as-is in that file (unused by this page now, but not
   this step's concern to clean up — Retirement may still reference them).
   Text stays "Run Comparison", not "Calculate" — PvS compares two
   strategies, not a single calculation; confirmed with the requester
   before implementing. */

/* ── SAVE / LOAD / SHARE ROW ─────────────────────────────────
   New in Step 3 — PvS previously had a 2x2 Export/Print/Reset/Share grid
   plus a separate Save/Load row (removed from the visible footer; #btn_csv/
   #btn_print/#btn_reset stay in the DOM, hidden, since app1.js's listeners
   and the results-area .export-bar's proxy clicks both depend on those
   IDs existing — see the markup comment in property_vs_shares.html).
   Share moved out of that grid into this row instead, joining Save/Load,
   matching Mortgage/Offset/LMI/Retirement's shared footer shape.
   Values copied from mortgage-polish.css's .ret-scenario-row/.ret-scen-btn
   (identical to lmi-polish.css's copy) — Step 1 deliberately did not put
   this row in css/simulators.css (offset's version has real differences),
   so PvS gets its own local copy too, same as the other three. Unscoped
   (no body.calc prefix) since PvS doesn't use that pattern; .ret-scen-btn
   isn't a generic-enough name to need it either. */
.ret-scenario-row {
  display: flex; gap: 0.35rem; margin-top: 0.1rem;
}
.ret-scen-btn {
  flex: 1; display: inline-flex; align-items: center; justify-content: center;
  gap: 0.28rem; padding: 0.38rem 0.4rem;
  font-family: inherit; font-size: 0.72rem; font-weight: 600; letter-spacing: 0.03em;
  color: #3d5248; background: #f0f5f2; border: 1px solid #c8ddd3;
  border-radius: 6px; cursor: pointer; white-space: nowrap;
  transition: background 0.13s, border-color 0.13s, color 0.13s;
}
.ret-scen-btn:hover { background: #e6f2ec; border-color: #3db07e; color: #1a5236; }
.ret-scen-btn:active { background: #d4eae0; }
.ret-scen-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.ret-scen-btn--share { color: #1a5236; background: #edf7f2; border-color: #b3d9c4; }
.ret-scen-btn--share:hover { background: #d4ede2; border-color: #1a6b4a; }

/* ── SUMMARY BAR ─────────────────────────────────────────── */
.summary-bar {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px;
  margin-top: 8px;
}
.summary-bar-row {
  display: flex; justify-content: space-between; align-items: center;
  padding: 2px 0;
}
.summary-bar-key { font-size: .74rem; color: var(--text-secondary); }
.summary-bar-val { font-family: 'DM Mono', monospace; font-size: .72rem; color: var(--text-secondary); }
.summary-bar-val.gold { color: var(--gold); }

/* ── RESULTS PANEL ───────────────────────────────────────── */
/* CANONICAL PATTERN — calculator main-panel white background. Mirrors
   tepuy.css's `body.calc .main-layout > main { background: var(--surface);
   }` (section 14) — same var (--bg-surface here is PvS's own alias for
   the identical #ffffff value tepuy.css calls --surface), same intent:
   a flat white content panel over the page's pale --bg/--bg-base tint,
   so the panel doesn't look tinted by the ambient page background. */
/* No overflow-y here (was: auto) — an overflow:auto item in a stretch grid
   row contributes only its min-content height to the row's auto-sizing, so
   .main-content's row collapsed to ~1 viewport tall and this panel scrolled
   internally instead of the page growing. That's what broke .sidebar's
   position:sticky (see below): with the page never taller than one
   viewport, there was no scroll distance for it to stick through. Letting
   this panel size to its natural content height — same as Mortgage's/
   Retirement's plain, non-scrolling <main> — fixes both at once: the page
   scrolls normally, and background: var(--bg-surface) gives it Mortgage's
   flat white panel instead of the body's pale --bg-base showing through. */
/* min-width: 0 overrides the browser default of min-width: auto on grid
   items, which refuses to shrink a grid item below its content's own
   min-content size — normally invisible, but a wide table (see the
   "TABLE" section's CANONICAL PATTERN comment) has a large min-content
   width, and without this override that width propagates straight up
   through .results-panel into .main-content's grid track, blowing out
   the ENTIRE page's width instead of scrolling inside the table's own
   .table-wrap. Same fix tepuy.css applies on its own `main` for the
   identical reason (search tepuy.css for "prevent grid blowout"). */
.results-panel { padding: 20px; background: var(--bg-surface); min-width: 0; }

/* CONFIRMED BUG (2026-08) — js/app1.js's runCalculation() calls
   `#results_content.scrollIntoView({block:'start'})` after every Run
   Comparison. The native scrollIntoView API has no awareness of
   .navbar's position:fixed, so it lands #results_content's top flush
   with viewport y:0 — directly BEHIND the 60px-tall fixed navbar.
   Reproduced live with Playwright WebKit (the engine every iPhone
   uses) + the real calc engine driving a real render, not a
   simulated/stubbed one: the winner banner and its summary text render
   partially hidden under the translucent, blurred navbar immediately
   after the very first Run Comparison — before the user has scrolled
   or interacted further, which is exactly what reads as "sections gone
   blank/wrong" on a first glance. Did not reproduce in Chromium (its
   scrollIntoView happened to land far enough down to clear the navbar
   on this page's current content height) — but that's a coincidence of
   content length, not a fix; the same code will land short again the
   moment the content above shrinks. scroll-margin-top is the standard,
   engine-independent fix: it tells scrollIntoView to stop that many
   px earlier, regardless of which browser's scroll math is doing the
   landing. 60px matches the fixed navbar's own height (EXCEPTION 1 in
   the "TEPUY NAVBAR" section below) plus a few px of breathing room. */
#results_content { scroll-margin-top: 72px; }

/* ── EMPTY STATE ─────────────────────────────────────────── */
/* CONFIRMED BUG (2026-09) — height: 100% used to vertically-center this
   block within .results-panel back when .calc-explainer (its later sibling
   in the same <main>) was a short tabbed panel. Since the tabbed-to-
   long-form conversion (#315) made .calc-explainer ~10,000px tall,
   .results-panel's own height ballooned to match, and height: 100% made
   .empty-state balloon right along with it — centering its icon/title/text
   in the MIDDLE of that ~10,500px box, thousands of px below the fold.
   First-time visitors landed on a visually blank white panel even though
   the instructional copy was there in the DOM the whole time (confirmed
   live with Playwright: element visible, text present, computed height
   10,561px). height: 100% removed so the box sizes to its own content
   instead — min-height keeps the same visual footprint it always had when
   short, it just no longer stretches to match a tall unrelated sibling. */
.empty-state {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  min-height: 400px; text-align: center; gap: 14px; color: var(--text-muted);
}
.empty-icon { font-size: 3.2rem; opacity: .18; font-weight: 200; letter-spacing: -.05em; }
.empty-title { font-weight: 600; font-size: 1.35rem; color: var(--text-secondary); }
.empty-sub { font-size: .82rem; max-width: 340px; line-height: 1.75; }

/* WINNER BANNER — removed (2026-08, results-section cleanup). The "★
   winner banner" HTML block (results_content's first child) was deleted:
   it stacked a duplicate of the same $ figure/margin the Decision
   Summary Card and the Performance Overview KPI grid also show, three
   times over. See the HTML comment in calculators/property_vs_shares.html
   where the block used to be. All .winner-* / #winner_* rules below this
   point in the file (media queries, contrast-fix overrides) were removed
   with it — none of those selectors match anything any more.

   DO NOT re-join that selector pair into ".winner-*(slash)#winner_*". The
   sequence it forms is a comment terminator: it closed THIS comment seven
   lines early, the three remaining prose lines were then parsed as a
   selector, and CSS error recovery consumed forward to the next `{` —
   taking the entire .kpi-grid rule below with it. Measured on the running
   page before the fix: 0 .kpi-grid rules parsed from this file, computed
   display `block` not `grid`, gap `normal`, margin-bottom `0px`, and the
   four Performance Overview cards rendering as full-width stacked blocks.
   It shipped to production that way. test/css_comment_terminators.test.js
   now fails the build on any recurrence, in any stylesheet. */

/* ── KPI GRID ──────────────────────────────────────────────
   MOVED to css/calculators.css (2026-09), under "PERFORMANCE OVERVIEW KPI
   GRID". Everything that used to be here — .kpi-grid, .kpi-card,
   .kpi-card-delta, .kpi-value/.kpi-sub sizing, the property/shares/gold
   value colours, .kpi-value-irr, .kpi-vs and the .kpi-irr-bar-* split bar —
   plus the `@container pvs-main (max-width: 600px)` and `(max-width: 1100px)`
   queries that resized the grid.

   Why: the standing rule is that no calculator carries its own CSS for the
   sidebar, results, insights, tables or tabs. This file is loaded by one
   page; calculators.css is loaded by all five and already owned the
   .kpi-label/.kpi-value typography jointly with retirement.html's
   .insight-label/.insight-value.

   The container queries could not move as they were. They keyed on
   `@container pvs-main`, a container name only this page declares, so a copy
   of them in a shared file would never resolve anywhere. The replacement is
   intrinsic — `repeat(auto-fit, minmax(min(100%, 20rem), 1fr))` — which is
   the same auto-fit/minmax approach docs/OPEN-ITEMS.md records as canonical
   for this repo and the same one retirement.html's .insights uses.

   DO NOT re-add .kpi-* rules here. This file loads AFTER calculators.css on
   this page only for the stylesheets before it — calculators.css is last in
   property_vs_shares.html's <head>, so a redeclaration here would LOSE, fail
   silently, and read as "the shared rule is broken". */


/* ── TABS ─────────────────────────────────────────────────
   Retirement-parity pass (2026-08): full underline-indicator pattern
   ported from retirement.html's .rtab-bar/.rtab-btn/.rtab-btn--active —
   a genuine UX pattern change, not a color swap: was a filled-pill
   selection style (background fill + shadow on the active tab), now a
   bottom-border indicator (transparent border reserved on every tab so
   layout doesn't shift on activate; only the active tab's border-bottom
   goes solid). Verified against retirement.html's actual rendered
   computed styles (not just its authored CSS) — a "better balance"
   refinement block in tepuy.css targeting the same .rtab-bar/.rtab-btn
   classes turned out to be dead on retirement.html itself, shadowed by
   an inline <style> block later in that page's own document; the
   values below are what retirement.html actually renders.
   Structural values (padding/radius/border-bottom width/font-weight/
   letter-spacing/the reserved-space mechanic) are literal ports. Colors
   stay in PvS's own gold/clay family rather than retirement's green,
   consistent with every other color decision in this round — WCAG
   verified: --gold (active underline) vs white = 3.32:1 (clears the
   3:1 UI-component minimum); --gold-text (active/hover text) vs white
   ≈ 4.41:1, the same pre-existing token already used elsewhere on this
   page for AA-safe gold text.
   Left untouched (out of scope for this pass): the equal-width flex:1
   tab sizing and flex-wrap responsive behavior — retirement instead
   makes its (7-tab) bar horizontally scrollable, but PvS has 9 tabs and
   its existing wrap behavior is already tested; switching sizing/
   overflow mechanics is a bigger structural change than "port the
   indicator style" asked for. */
.tabs {
  display: flex; gap: 2px;
  background: #f7faf8;
  border: none;
  border-bottom: 1px solid #e3ede8;
  border-radius: 0;
  padding: 0.55rem 0.75rem 0;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.tab {
  flex: 1; padding: 0.35rem 0.85rem 0.4rem;
  border: none; background: transparent;
  border-radius: 6px 6px 0 0;
  border-bottom: 2px solid transparent;
  position: relative; bottom: -1px;
  color: var(--text-muted);
  /* font-family: inherit — NOT redundant on a <button>: browsers don't
     cascade body's font into form controls (button/input/select/
     textarea) via normal inheritance; Chromium's own UA default for a
     bare <button> here computes to plain "Arial", confirmed live. The
     very first pass at this font audit removed this line assuming it
     was a harmless duplicate of body's stack, same as the non-button
     fixes elsewhere in this pass — that broke it (verified: computed
     font-family became "Arial"). The Decision Summary Card's share
     button had this figured out correctly before the audit touched
     anything, and the other buttons here were brought in line with it
     rather than the reverse; that button and its rule are both gone
     now, but the reasoning it established still applies below. */
  font-family: inherit;
  font-size: .68rem; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase;
  cursor: pointer; transition: var(--transition), border-bottom-color .15s;
  white-space: nowrap;
}
.tab:hover { color: var(--gold-text); }
.tab.active {
  background: #ffffff;
  color: var(--gold-text);
  border-bottom-color: var(--gold);
  font-weight: 800;
  box-shadow: none;
}

.tab-pane { display: none; }
.tab-pane.active { display: block; }

/* ── CHART CARDS ─────────────────────────────────────────── */
.chart-card {
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 18px;
  margin-bottom: 14px;
}
.chart-title {
  font-size: .7rem; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 14px;
  display: flex; align-items: center; gap: 7px;
}
/* Chart.js with maintainAspectRatio:false fills its container height.
   Wrap the canvas in a div capped at 85vh so charts never dominate the screen. */
.chart-wrap {
  position: relative;
  height: min(360px, 62vh); /* comfortable default; never taller than 62vh */
  max-height: 62vh;
  width: 100%;
}
canvas { width: 100% !important; height: 100% !important; }

/* ── MC STATS ────────────────────────────────────────────── */
.mc-stats-grid {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: 8px; margin-top: 14px;
}
.mc-stat {
  background: var(--bg-raised); border: 1px solid var(--border);
  border-radius: var(--radius-md); padding: 11px; text-align: center;
}
.mc-stat-label { font-size: .65rem; color: var(--text-secondary); letter-spacing: .05em; text-transform: uppercase; margin-bottom: 5px; }
.mc-stat-val { font-family: 'DM Mono', monospace; font-size: .95rem; font-weight: 500; }

/* MC methodology note */
.mc-note {
  margin-top: 10px;
  font-size: .68rem;
  color: var(--text-muted);
  padding: 8px 10px;
  background: var(--bg-raised);
  border-radius: var(--radius-sm);
  border-left: 2px solid var(--gold-dim);
  line-height: 1.6;
}
.mc-note strong { color: var(--gold); }

/* ── TABLE ───────────────────────────────────────────────── */
/* CANONICAL PATTERN — horizontally-scrollable data table. .table-wrap
   already had overflow-x: auto, so on paper every table here (year-by-
   year, depreciation, sensitivity, tornado) should already scroll on
   mobile — but `table { width: 100% }` below capped every table at
   exactly its container's width, so it could never grow wider than
   .table-wrap and there was nothing to scroll: columns just got
   squeezed illegibly narrow instead. min-width: 100% (not width: 100%)
   keeps the same "fill the container on desktop" look when the content
   fits, while letting the table grow past 100% and trigger the
   wrapper's real horizontal scroll once it doesn't — same fix needed
   for a future calculator's own data table: overflow-x: auto on the
   wrapper is necessary but not sufficient; the table inside it must be
   allowed to exceed the wrapper's width. */
.table-wrap {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  /* Discoverability: overflow-x:auto's native scrollbar is easy to miss
     on mobile (many browsers hide it entirely until mid-scroll). A
     persistent right-edge fade is the standard "there's more here"
     affordance — background-attachment:local vs (default) scroll is
     what makes the two inner gradients scroll WITH the table content
     while the outer two solid blocks stay pinned to the wrapper's own
     edges, so the fade only shows while there's unscrolled content
     left in that direction (it disappears at each scroll extreme). */
  background:
    linear-gradient(to right, var(--bg-surface) 30%, rgba(255,255,255,0)) 0 0,
    linear-gradient(to left, var(--bg-surface) 30%, rgba(255,255,255,0)) 100% 0,
    linear-gradient(to right, rgba(15,17,24,.12), rgba(15,17,24,0) 100%) 0 0,
    linear-gradient(to left, rgba(15,17,24,.12), rgba(15,17,24,0) 100%) 100% 0;
  background-repeat: no-repeat;
  background-color: var(--bg-surface);
  background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
  background-attachment: local, local, scroll, scroll;
}
/* Small explicit hint text on top of the fade, narrow screens only —
   the fade alone can read as a design flourish rather than "scroll me"
   at a glance; spelling it out removes the ambiguity. Hidden once the
   table actually fits without scrolling (>= 700px, matching PvS's own
   .edu-glossary single-column breakpoint) since there's nothing to
   discover there. */
.table-wrap::before {
  content: '⟷ Scroll to see all columns';
  display: block;
  padding: 6px 11px 0;
  font-size: .68rem;
  font-weight: 600;
  color: var(--text-muted, #7a8a9a);
  text-align: right;
}
@container pvs-main (min-width: 700px) {
  .table-wrap::before { display: none; }
}
table { width: auto; min-width: 100%; border-collapse: collapse; font-family: 'DM Mono', monospace; font-size: .7rem; }
/* FONT FIX (2026-08, table-font audit) — thead th used to inherit
   table's DM Mono uncontested. Checked against mortgage.html's own
   amortisation schedule table live: its <th> AND <td> both compute to
   plain "Inter Tight" — mortgage doesn't monospace any of its table,
   headers or numbers. This table's own column headers ("Year", "Prop
   Value", "Loan Balance", the "Property"/"Shares"/etc. group headers)
   are labels, not data, so they get the same explicit Inter Tight
   override thead th[title]:hover::after already needed further down
   this file for the identical reason: `thead th { font-family: inherit
   }` would NOT reach body's font here — the nearest ancestor setting
   font-family is <table> itself (DM Mono, intentionally, for the
   numeric td cells below), so inherit would just re-inherit DM Mono
   from it. The literal stack has to be spelled out to actually reach
   past that ancestor.
   tbody td is DELIBERATELY left on DM Mono, unlike mortgage's own
   table: every column here is a dollar figure, percentage, or Y/N
   flag in a genuinely dense, many-column financial table (mortgage's
   schedule has 7 columns; this one has 50+), where monospace digit
   alignment carries real value mortgage's simpler table doesn't need.
   That's a deliberate PvS-specific choice, not an oversight — matching
   mortgage's table font exactly was considered and rejected here. */
thead th {
  background: var(--bg-raised); padding: 9px 11px;
  text-align: right; font-size: .66rem; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase; color: var(--text-secondary);
  border-bottom: 1px solid var(--border); white-space: nowrap; position: relative;
  font-family: 'Inter Tight', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial,
               'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
}
thead th:first-child { text-align: left; }

/* Section header row spans property / shares column groups */
.section-header-prop,
.section-header-shares,
.section-header-exit {
  text-align: center !important; font-size: .65rem;
  padding: 6px 10px; letter-spacing: .06em; border-bottom: 2px solid transparent;
}
.section-header-prop   { color: var(--property) !important; border-bottom-color: var(--property); background: color-mix(in srgb, var(--clay, #C97A3A) 8%, transparent) !important; }
.section-header-shares { color: var(--shares)   !important; border-bottom-color: var(--shares);   background: color-mix(in srgb, var(--moss, #4C7A5B) 8%, transparent) !important; }
.section-header-exit   { color: var(--warning)  !important; border-bottom-color: var(--warning);  background: rgba(245,166,35,.07) !important; }

/* Tooltip icon inside column header */
.th-tip { display: inline-block; font-size: .55rem; opacity: .5; cursor: help; vertical-align: super; margin-left: 2px; font-style: normal; transition: opacity .15s; }
thead th[title]:hover .th-tip { opacity: 1; }
thead th[title]:hover { background: var(--bg-hover) !important; color: var(--text-primary) !important; cursor: help; }

tbody tr { border-bottom: 1px solid var(--border); transition: background .12s; }
tbody tr:last-child { border-bottom: none; }
tbody tr:hover { background: var(--bg-raised); }
tbody td { padding: 7px 11px; text-align: right; color: var(--text-secondary); }
tbody td:first-child { text-align: left; color: var(--text-secondary); }
.td-property { color: var(--property) !important; }
.td-shares   { color: var(--shares) !important; }
.td-exit     { color: var(--warning) !important; opacity: 0.85; }
.td-exit-highlight { color: var(--warning) !important; font-weight: 600; background: rgba(245,166,35,.08) !important; }
.td-pos      { color: var(--success) !important; }
.td-neg      { color: var(--danger) !important; }
.td-gold     { color: var(--gold) !important; }
.row-highlight td { background: rgba(201,168,76,.04); }
.yr-age { color: var(--text-muted); font-size: .6rem; margin-left: 4px; }

/* ── ASSUMPTIONS ─────────────────────────────────────────── */
.assumptions-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 14px; }
.assumption-card {
  background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: var(--radius-md); padding: 14px;
}
.assumption-card h4 {
  font-size: .65rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-muted); margin-bottom: 10px;
  padding-bottom: 7px; border-bottom: 1px solid var(--border);
}
.assumption-row { display: flex; justify-content: space-between; align-items: center; padding: 3px 0; }
.assumption-key { font-size: .68rem; color: var(--text-secondary); }
.assumption-val { font-family: 'DM Mono', monospace; font-size: .68rem; color: var(--gold); }

/* ── SENSITIVITY TABLE ───────────────────────────────────── */
.sensitivity-grid table th, .sensitivity-grid table td { text-align: center; }
.cell-green { background: color-mix(in srgb, var(--moss, #4C7A5B) 10%, transparent); color: var(--shares) !important; }
.cell-red   { background: rgba(224,85,85,.08);  color: var(--danger) !important; }

/* ── EXPORT BAR ──────────────────────────────────────────── */
/* .export-bar/.btn-export moved to css/calculators.css — 2026-08 Stage 2.
   (.export-bar is still referenced by selector in the @media print rule
   further down this file — that's fine, it doesn't need its own rule
   here to be a valid selector reference.) */

/* ── SECTION INTRO ───────────────────────────────────────── */
.section-intro {
  font-size: .74rem; color: var(--text-secondary);
  margin-bottom: 10px; line-height: 1.65;
  padding: 7px 9px;
  background: var(--bg-input);
  border-radius: var(--radius-sm);
  border-left: 2px solid var(--gold-dim);
}

/* ── DR BADGE ────────────────────────────────────────────── */
.dr-badge {
  display: inline-block;
  background: rgba(240,100,180,.08);
  border: 1px solid rgba(240,100,180,.22);
  border-radius: 99px; padding: 1px 7px;
  font-size: .58rem; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase;
  color: #f064b4; margin-left: 5px;
}

/* ── LOADING OVERLAY ─────────────────────────────────────── */
.loading-overlay {
  display: none; position: fixed; inset: 0;
  background: rgba(13,15,20,.75);
  z-index: 999; align-items: center; justify-content: center;
  backdrop-filter: blur(4px);
}
.loading-overlay { background: rgba(244,245,248,.75); }
.loading-overlay.visible { display: flex; }
.loading-spinner {
  width: 40px; height: 40px;
  border: 3px solid var(--border);
  border-top-color: var(--gold);
  border-radius: 50%;
  animation: spin .6s linear infinite;
}
.loading-label {
  color: var(--text-secondary);
  font-size: .8rem; margin-top: 14px; text-align: center;
}
.loading-wrap { display: flex; flex-direction: column; align-items: center; gap: 6px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ── DIVIDER ─────────────────────────────────────────────── */
.divider { height: 1px; background: var(--border); margin: 10px 0; }

/* ── RESPONSIVE ──────────────────────────────────────────── */
/* .kpi-grid's 1100px container query removed with the rest of the KPI
   block — the shared grid in calculators.css is intrinsically responsive. */
@container pvs-layout (max-width: 1200px) {
  body.calc .main-layout { grid-template-columns: 320px 1fr; }
}
/* Key Wide -> Medium/Narrow tier threshold (PvS's own tuned value —
   equivalent to the 799.98px threshold the other calculators share via
   tepuy.css, kept at PvS's original 900px rather than forced to match). */
@container pvs-layout (max-width: 900px) {
  body.calc .main-layout { grid-template-columns: 1fr; }
  body.calc .calc-aside { height: auto; position: static; align-self: auto; }

  /* #page-head-placeholder now lives inside .results-panel (moved 2026-08
     so its width matches the main column on desktop — see .page-head
     above) but on mobile it still needs to render ABOVE .sidebar, same
     reading order as before the move. display:contents flattens
     .results-panel so its children become direct grid items of
     .main-content, letting `order` place the hero first without moving
     anything in the DOM — the same trick tepuy.css uses for Mortgage/
     Retirement's own #page-head-placeholder at their narrow tier. */
  body.calc .main-layout > .results-panel { display: contents; }
  body.calc .main-layout > .results-panel > #page-head-placeholder { order: 1; }
  body.calc .main-layout > .calc-aside { order: 2; }
  body.calc .main-layout > .results-panel > :not(#page-head-placeholder) {
    order: 3;
    /* .results-panel's own min-width: 0 (see "RESULTS PANEL" above) no
       longer applies to anything once it's display: contents — its
       children are the real grid items now, each needing the same
       override for the same reason (a wide table's min-content width
       must not blow out the page; see the "TABLE" section). */
    min-width: 0;
  }
}
@container pvs-main (max-width: 600px) {
  .assumptions-grid { grid-template-columns: 1fr; }
  .mc-stats-grid { grid-template-columns: 1fr 1fr; }
}

/* ── PRINT ───────────────────────────────────────────────── */
@media print {
  .calc-aside, header, .export-bar, .loading-overlay { display: none !important; }
  body.calc .main-layout { grid-template-columns: 1fr; }
  body.calc .main-layout > .results-panel { padding: 0; }
  .chart-card { break-inside: avoid; }
}

/* ─── v5 ADDITIONS ────────────────────────────────────────────── */

/* Info tip tooltip (.info-tip / .info-tip-popup) moved to
   css/calculators.css — 2026-08 Stage 2. Its position:fixed /
   js/pvs-tooltip.js mechanism travels with it unchanged. The *separate*
   native-title-attribute tooltip for table headers below
   (thead th[title]::after) is a different, PvS-only mechanism and
   stays here. */
/* table header tooltip — needs higher z and wider */
thead th[title]:hover::after {
  content: attr(title);
  position: absolute;
  top: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  min-width: 200px;
  max-width: 300px;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: 9px 12px;
  font-size: .68rem;
  line-height: 1.6;
  color: var(--text-secondary);
  z-index: 300;
  box-shadow: var(--shadow-lg);
  white-space: normal;
  pointer-events: none;
  font-family: 'Inter Tight', sans-serif;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
}
thead th[title] { position: relative; }

/* PPOR note */
.ppor-note {
  background: rgba(201,168,76,.10);
  border: 1px solid rgba(201,168,76,.25);
  border-radius: var(--radius-md);
  padding: 8px 12px;
  font-size: .71rem;
  color: var(--gold-light);
  margin: 4px 0 8px;
  line-height: 1.5;
}

/* ── EDUCATIONAL SECTION ─────────────────────────────────────────── */
/* "Learn & Reference" (.edu-*) moved to css/calculators.css — 2026-08
   Stage 2. Consolidated from 3 competing passes scattered across this
   file (this base rule plus two later override passes further down,
   see the "EDU PANEL" and "COMPREHENSIVE CONTRAST FIX v2" sections
   below) into one clean definition per selector in the shared file,
   and the panel-heading background was deliberately changed from a
   cream tint to white per the Stage 2 plan — see calculators.css. */

/* ─── v5.1 ADDITIONS ──────────────────────────────────────────── */

/* .btn-pdf moved to css/calculators.css — 2026-08 Stage 2. */

/* .insights-bar and .insights-title removed here (2026-08): dead code —
   both targeted markup (#insights_bar and its "Key Insights" title div)
   that no longer exists on the page, deleted when Key Insights moved
   into its own tab earlier today. .insights-list/li below are kept —
   that markup is still live inside the Insights tab pane. */
.insights-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.insights-list li {
  font-size: .8rem;
  color: var(--text-primary);
  opacity: .88;
  padding: 4px 0;
  border-bottom: 1px solid rgba(201,168,76,.1);
  line-height: 1.6;
}
.insights-list li:last-child { border-bottom: none; }
.insights-list li::before { content: '• '; color: var(--gold); }

/* Light mode stronger text in inputs */
input,
select,
textarea {
  color: #0f1118;
}
label { color: #2c3248; }
.hint { color: #505870; }

/* Better mobile layout — split from the original combined query: the
   stacking/overlap-prevention rules are a pvs-layout concern (redundant
   with the 900px stacking rule above for .main-content, but preserved
   as-is rather than deduplicated), while kpi-grid/winner-banner are sized
   against the results panel's own width (pvs-main). */
@container pvs-layout (max-width: 768px) {
  body.calc .main-layout {
    grid-template-columns: 1fr;
  }
  body.calc .calc-aside {
    max-height: none;
    position: relative;
    /* CONFIRMED BUG (2026-08) — the base `.sidebar` rule (Wide tier) sets
       top: 60px, meaningful there because position is sticky. That top
       value is inert under both position: static (900px tier above) and
       the OLD position here — but position: relative DOES honor top/left/
       right/bottom offsets, and this rule never reset it. The result:
       switching to position: relative silently reactivated a 60px
       downward visual shift that was previously harmless, pushing
       .sidebar 60px into whatever renders after it (#results_content) —
       confirmed live with Playwright WebKit + a real calc-engine-driven
       render: .sidebar's bottom edge lands ~36px past #results_content's
       top after Run Comparison's scrollIntoView, visibly overlapping the
       winner banner with the sidebar's Save/Load Scenario buttons. A
       relatively-positioned element with an inherited offset and no
       layout-affecting side effect is exactly the kind of latent trap
       that survives until some OTHER change (like position finally
       becoming relative) makes it real — reset explicitly here rather
       than relying on the cascade not changing again upstream. */
    top: auto;
  }
  .results-panel {
    padding: 12px;
    /* No margin-top here anymore (was: 40px, "prevent overlap with
       sidebar buttons") — dead weight since the 900px tier above made
       .results-panel display:contents, which strips its own box
       (padding/margin included) so its children can flatten into
       .main-content's flex order alongside .sidebar. A margin-top on a
       display:contents element has nothing to apply to. The equivalent
       clearance now lives directly on #pvs_shared_banner/.empty-state/
       #results_content below — the actual elements that render right
       after .sidebar once stacked. */
  }
  /* The real fix for the stacked-mobile clearance the rule above used to
     provide: applied directly to the elements that now render immediately
     after .sidebar (order: 2) in the flattened order: 3 group, since
     .results-panel itself no longer has a box to hang a margin off of. */
  #pvs_shared_banner,
  .empty-state,
  #results_content {
    margin-top: 24px;
  }
}
/* Two more .kpi-grid container queries removed here (2026-09) with the rest
   of the KPI block — the shared grid in css/calculators.css sizes itself from
   its own width via auto-fit/minmax and needs no breakpoint. */
@container pvs-layout (max-width: 480px) {
  header { padding: 0 12px; }
  /* .edu-tabs .edu-tab responsive override moved to css/calculators.css
     — 2026-08 Stage 2. */
}

/* ═══════════════════════════════════════════════════════════════
   TEPUY NAVBAR — now shares tepuy.css's rules via the normal cascade
   (tepuy.css is loaded before this file — see the <link> order in
   property_vs_shares.html). This section used to carry a full parallel
   copy of every .navbar/.logo-title/.nav-links/.sub-menu/.hamburger/
   .cta-button/.plan-badge rule tepuy.css already defines for the exact
   same shared markup (includes/navbar.html) — that's why fixes here kept
   being incomplete: each patch matched one property while the copy
   itself stayed in place to drift on the next one. Everything tepuy.css
   already styles identically has been deleted; only genuine, functional
   exceptions remain below, each explained.
   ═══════════════════════════════════════════════════════════════ */

/* EXCEPTION 1 — height math. PvS's own layout (.sidebar, .results-panel,
   .main-content) is hardcoded around a 60px-tall navbar (height: calc(
   100vh - 60px), top: 60px, etc. — search this file for "60px" if that
   ever needs to change). tepuy.css's own ".navbar-inner" only guarantees
   min-height: 64px, and ".navbar" itself sets no height at all — so
   height: 60px must stay pinned here on both, or PvS's sidebar/results
   layout would drift out of alignment with the navbar. */
.navbar { height: 60px; }
.navbar-inner { height: 60px; }

/* EXCEPTION 2 (retired 2026-08) — this used to force the navbar to
   position: sticky instead of tepuy.css's own position: fixed, on the
   theory that PvS's navbar "has always been sticky... in normal flow,
   reserving its own space naturally." That was never actually true in a
   way that worked: <header>'s containing block for sticky purposes is
   #navbar-placeholder, a box exactly as tall as the header itself — with
   zero room for "sticky" to hold onto, it just scrolled away like a
   normal in-flow element (confirmed live: the navbar tracked scrollY
   1:1, on every load). This override, plus the equally-guilty (and now
   also removed) `header:not(.page-head){position:sticky}` rule above,
   is why the navbar didn't stay visible while scrolling — the one
   thing every other calculator's navbar does correctly, unopposed,
   straight from tepuy.css. Deleting both lets ".navbar { position: fixed
   }" cascade through as-is, matching Mortgage/Offset vs Shares/
   Retirement exactly — this IS the canonical calculator navbar pattern;
   a future calculator needs zero navbar CSS of its own for this to work,
   same as those three. body's padding-top: 60px (see above) is the other
   half of this fix — required for a fixed navbar, restored there. */

/* EXCEPTION 3 (retired) — this used to key a dark navbar tint off PvS's
   own light/dark toggle, which is now removed entirely (palette redesign
   2026-08: no page keeps a dark navbar or a theme toggle). tepuy.css's
   base ".navbar" rule (bone-tinted) applies with zero PvS CSS needed,
   exactly like every other calculator/blog page. */

/* EXCEPTION 4 — mobile menu positioning AND opacity. tepuy.css's shared
   mobile dropdown is position: absolute, anchored below the navbar. That
   trips a real WebKit bug on iOS Safari (an absolutely-positioned child
   of a position: sticky ancestor scrolls/repaints incorrectly), so PvS's
   panel uses fixed positioning + safe-area insets + a GPU-compositing
   hint instead — a full-height sheet rather than a dropdown.
   Border/text color are NOT redeclared: they still come from tepuy.css's
   own mobile rule via the same --nav-text/--nav-border custom properties
   Exception 3 sets. Background IS redeclared, at higher opacity than
   Exception 3's 68%/tepuy.css's 82% — that level is tuned for a slim bar
   or a small dropdown sitting over a limited area, which is what it is
   on every other page. Here it's behind a full-height sheet covering
   this page's own busy content (hero text, badges), where the same
   opacity let that content visibly bleed through — confirmed by
   screenshot, not assumed. 92% matches PvS's own prior tuning for this
   exact full-height-sheet case, just recomputed from tepuy.css's brand
   colors instead of PvS's old --bg-surface token.
   Breakpoint matches tepuy.css's own (768px) — this used to be a
   mismatched 900px, which meant PvS alone showed its mobile hamburger
   menu in the 768–900px tablet range while every other page still showed
   the full desktop nav-links row. */
@media (max-width: 768px) {
  .navbar {
    -webkit-transform: translateZ(0);
    transform: translateZ(0);
    will-change: transform;
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
  }
  .navbar .nav-links {
    position: fixed;
    top: 60px;
    left: 0;
    right: 0;
    max-height: calc(100vh - 60px);
    padding-bottom: max(12px, env(safe-area-inset-bottom, 12px));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    z-index: 999;
  }
  .navbar .nav-links {
    background: color-mix(in srgb, var(--bone) 92%, transparent);
  }
}

/* EXCEPTION 5 — wordmark + plan-badge font-family. tepuy.css's ".navbar
   .logo-title" and ".plan-badge" rules only set font-weight/size/color
   (and radius/background for the badge), not font-family — on pages
   that load ONLY tepuy.css, they don't need to: both just inherit 'Inter
   Tight' from tepuy.css's own "body" rule. Retirement-parity pass
   (2026-08): this override is now redundant (PvS_style.css's own body
   rule was repointed to 'Inter Tight' too, so the inheritance these two
   selectors were fighting for no longer disagrees), but left in place
   rather than removed — harmless belt-and-suspenders, and removing it
   is a needless risk for zero visual change. */
.logo-title,
.plan-badge {
  font-family: 'Inter Tight', system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

/* No tepuy.css equivalent exists for active-nav-link highlighting (it
   has no concept of a "current page" state in the shared nav) — kept as
   a genuine PvS-only addition, not a duplicate of anything. */
.nav-links > a.active,
.nav-links > a[aria-current="page"] {
  color: var(--gold);
  background: rgba(201,168,76,.1);
}

/* EDU PANEL "Behind the Math" readability fix + LIGHT MODE stronger-text
   pass's .edu-* lines: both moved to css/calculators.css, consolidated,
   as part of the 2026-08 Stage 2 Learn & Reference extraction. */

/* ═══════════════════════════════════════════════════════════════
   LIGHT MODE — stronger text throughout
   ═══════════════════════════════════════════════════════════════ */

.field label { color: #1a2030 !important; font-weight: 500; }
.hint, .range-val { color: #4a5068 !important; }
/* .kpi-label / .kpi-value colour overrides removed (2026-09). Both were
   hardcoded hexes with !important, and the .kpi-value one silently beat the
   per-winner colour the card is supposed to carry — every value rendered the
   same near-black regardless of which side won. Label colour now comes from
   var(--text-secondary) in css/calculators.css; value colour from the
   .kpi-value--prop / .kpi-value--shares classes js/app1.js applies. */
/* .tab / .tab.active dark-navy !important overrides removed here
   (2026-08): leftover from the old dark-theme-era "stronger text" patch,
   already dead before this pass (both were silently beaten by the
   #374060/#0f1118 !important pair further down this file — see the
   "Tabs" section removed alongside this one), and would now also fight
   the ported underline-tab design's gold-text/font-weight:800 active
   state. Confirmed removal doesn't affect anything: the tab redesign's
   own base rule sets final, correct, WCAG-checked colors directly. */
table th { color: #0f1118 !important; }
table td { color: #1a2030 !important; }
/* .edu-header-title/.edu-tab/.edu-tab.active/.edu-glossary dt/dd color
   overrides moved to css/calculators.css — 2026-08 Stage 2. */
.insights-list li { color: #1a2030 !important; }

/* Pro gate notice */
/* .pro-gate-notice removed — no pro gating */

/* ═══════════════════════════════════════════════════════════════
   DISCLAIMER FOOTER
   ═══════════════════════════════════════════════════════════════ */
.disclaimer-footer {
  background: rgba(180,40,40,.07);
  border-top: 1px solid rgba(180,40,40,.2);
  padding: 10px 24px;
  position: sticky;
  bottom: 0;
  z-index: 80;
  backdrop-filter: blur(8px);
}
.disclaimer-inner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  max-width: 1400px;
  margin: 0 auto;
  font-size: .71rem;
  color: var(--text-secondary);
  line-height: 1.5;
}
.disclaimer-icon { font-size: .9rem; flex-shrink: 0; margin-top: 1px; }
.disclaimer-inner strong { color: var(--text-primary); }
.disclaimer-inner a { color: var(--gold-text); text-decoration: underline; }

.disclaimer-footer {
  background: rgba(180,40,40,.05);
}
.disclaimer-inner { color: #505870; }
.disclaimer-inner strong { color: #0f1118; }

/* field-note utility */
.field-note {
  font-size: .65rem;
  line-height: 1.5;
  margin-top: 4px;
}



/* ═══════════════════════════════════════════════════════════════
   LOGO FIX — hard cap so the image can never overflow header
   ═══════════════════════════════════════════════════════════════ */
/* .calc-header-logo removed — logo only in top navbar */

/* ═══════════════════════════════════════════════════════════════
   BASIC / ADVANCED MODE TOGGLE BAR — moved to css/simulators.css.

   This block was left behind by #269, which shared the pill chrome but not
   the bar/label/group. Because this file loads AFTER simulators.css, its
   equal-specificity copies of .mode-toggle-label and .mode-toggle-group won,
   and the shared component's values never reached this page. Measured: the
   inset track rendered radius 4px / background rgb(247,248,251) here against
   the shared 8px / #fff — the two pages were still drawing different
   controls, from different files, while looking like they shared one.

   .mode-toggle-bar, .mode-toggle-label, .mode-toggle-group, .mode-btn,
   .mode-btn:hover, .mode-btn.active and .mode-hint all live in
   css/simulators.css now, with the markup in js/mode-toggle.js.
   Do not reinstate any of them here.
   ═══════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════
   SCENARIO SAVE / LOAD BUTTONS & DROPDOWN
   Moved to css/calculators.css — 2026-08 Stage 2, as part of the shared
   export/print/reset/save/load button strip (.btn-scenario,
   .scenario-auth-hint, .scenario-load-dropdown, .sld-*, plus the
   @keyframes fadeIn it used, which had no other consumer in this file).
   ═══════════════════════════════════════════════════════════════ */

/* .section-icon font-family override removed — the icon system itself
   (markup + .section-icon/.icon-* CSS) was removed in the Step 3 sidebar
   rebuild; nothing to style. */

/* Login/Signup button in navbar (triggers Auth0 directly) */
.nav-login-btn {
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  font-family: 'Inter Tight', sans-serif;
  font-size: .82rem;
  font-weight: 500;
  padding: 6px 12px;
  cursor: pointer;
  transition: var(--transition);
  white-space: nowrap;
}
.nav-login-btn:hover {
  color: var(--gold);
  border-color: var(--gold-dim);
  background: rgba(201,168,76,.07);
}
.nav-login-btn { color: #2c3248; }
.nav-login-btn:hover { color: #0f1118; background: #eaecf2; border-color: var(--gold); }

/* Assumption card heading: brighter */
.assumption-card h4 {
  font-size: .67rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-secondary); margin-bottom: 10px;
  padding-bottom: 7px; border-bottom: 1px solid var(--border);
}





/* ============================================================================
   v6 Cashflow Neutrality UI
============================================================================ */

.cashflow-verification .chart-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.cfv-status {
  font-size: 0.95rem;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.10);
}

.cfv-status.ok {
  border-color: rgba(60, 220, 150, 0.35);
  background: rgba(60, 220, 150, 0.12);
}

.cfv-status.bad {
  border-color: rgba(255, 120, 120, 0.35);
  background: rgba(255, 120, 120, 0.12);
}

.cfv-meta {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 10px;
  padding: 10px 14px 0;
}

.cfv-meta .k {
  display: inline-block;
  min-width: 84px;
  opacity: 0.8;
}

.cfv-meta .v {
  font-weight: 600;
}

.cfv-table table {
  width: 100%;
}

.cfv-table tbody tr.ok td {
  opacity: 0.92;
}

.cfv-table tbody tr.bad td {
  opacity: 0.92;
}

.cfv-table tbody tr.bad td:last-child {
  font-weight: 700;
}





/* ============================================================
   ADDITIONS — extracted from inline HTML styles + new features
   Organised: Share buttons → DSC → Share Card → MC note →
              Shared banner → Light-mode contrast → Font floor
   ============================================================ */


    /* .btn-share/.btn-share-export moved to css/calculators.css —
       2026-08 Stage 2. */
    /* The Decision Summary Card's rules stood here. The card is gone from
       calculators/property_vs_shares.html, so every selector in this block
       matched nothing: #decision_summary_card (+ ::before, + .visible),
       .dsc-headline, .dsc-winner-label (+ .property/.shares), .dsc-insights,
       .dsc-insight-item, .dsc-insight-label, .dsc-insight-value (+ .teal/
       .gold/.warn), .dsc-assumption-strip (+ strong), .dsc-footer,
       .dsc-legal, .dsc-share-btn (+ :hover/.copied), and the @container
       query that resized two of them.

       Three of those were already dead before this change and are worth
       naming so they are not re-added by pattern: .dsc-copy-tick,
       .dsc-copy-label and .dsc-share-btn.copied styled a copy-confirmation
       state whose markup never existed — the button's only child was a bare
       <span>. The Share Result button that replaced it is a .btn-export in
       the results-area export bar and takes that bar's styling.

       --dsc-teal and --dsc-teal-text went with them: the removed rules
       were their only consumers anywhere in the repo. --gold-text stays;
       it has many. */


    /* ── Shared-scenario banner (shown when URL params present) ── */
    #pvs_shared_banner {
      display: none;
      background: linear-gradient(135deg, rgba(201,168,76,0.12), rgba(201,168,76,0.05));
      border: 1px solid var(--gold-dim, #8a6d28);
      border-radius: 8px;
      padding: 10px 16px;
      margin: 0 0 16px 0;
      font-size: 0.82rem;
      color: var(--gold, #c9a84c);
      align-items: center;
      gap: 8px;
      line-height: 1.4;
    }
    #pvs_shared_banner.visible { display: flex; }
    #pvs_shared_banner strong { color: var(--text-primary, #e8e0d0); }
  


/* ══ SHARE CARD OVERLAY ═══════════════════════════════════════════════════════
   A full-screen modal containing an isolated, screenshot-ready result card.
   Fixed 600px wide, always dark, designed to be captured by html2canvas.
═══════════════════════════════════════════════════════════════════════════ */
#share_card_overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0,0,0,0.82);
  z-index: 9000;
  align-items: center;
  justify-content: center;
  padding: 24px 16px;
  backdrop-filter: blur(4px);
}
#share_card_overlay.visible { display: flex; }

#share_card_outer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  width: 100%;
  max-width: 640px;
}

/* The card itself — always dark, fixed width, screenshot target */
#share_card {
  width: 600px;
  max-width: 100%;
  background: #111520;           /* slightly lighter than pure black — tiles now visible */
  border-radius: 18px;
  padding: 28px 28px 22px;
  position: relative;
  overflow: hidden;
  font-family: 'Inter Tight', sans-serif;
  box-shadow: 0 24px 80px rgba(0,0,0,0.9);
}

/* Accent bar top */
#share_card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--chart-property) 0%, var(--chart-shares) 100%);
}

/* Subtle grid — reduced opacity so it doesn't muddy contrast */
#share_card::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,0.018) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.018) 1px, transparent 1px);
  background-size: 40px 40px;
  pointer-events: none;
}

/* Header row: winner badge + Tepuy brand */
.sc-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 18px;
  gap: 12px;
}
.sc-brand {
  font-family: 'Inter Tight', sans-serif;
  font-weight: 600;
  font-size: 0.82rem;
  letter-spacing: 0.05em;
  color: rgba(255,255,255,0.50);   /* was 0.28 — much more readable */
  text-align: right;
  line-height: 1.4;
  flex-shrink: 0;
}
.sc-brand span {
  display: block;
  font-family: 'DM Mono', monospace;
  font-size: 0.72rem;              /* was 0.60 */
  letter-spacing: 0.04em;
  color: rgba(255,255,255,0.35);   /* was 0.18 */
  margin-top: 2px;
}

.sc-winner-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.74rem;              /* was 0.65 */
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 5px 12px;
  border-radius: 6px;
}
/* On the dark share card (#111520) the mark weights are far too dark to read,
   so both sides lighten toward white. --gold-light is the existing 70%-clay
   companion; --moss-light is its counterpart, added alongside the token pair.
   The badge also carries the winning side's NAME as text, so it never depends
   on the colour to say which side won. */
.sc-winner-badge.property {
  background: color-mix(in srgb, var(--clay, #C97A3A) 22%, transparent);
  color: var(--gold-light);
  border: 1px solid color-mix(in srgb, var(--clay, #C97A3A) 45%, transparent);
}
.sc-winner-badge.shares {
  background: color-mix(in srgb, var(--moss, #4C7A5B) 22%, transparent);
  color: var(--moss-light);
  border: 1px solid color-mix(in srgb, var(--moss, #4C7A5B) 45%, transparent);
}

/* Main headline */
.sc-headline {
  font-family: 'Inter Tight', sans-serif;
  font-weight: 600;
  font-size: 1.32rem;
  line-height: 1.42;
  color: #dde2ee;                  /* slightly softer than pure white for long text */
  margin-bottom: 20px;
  letter-spacing: -0.01em;
}
.sc-headline strong {
  color: #ffffff;
}

/* 2×2 stat grid */
.sc-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 20px;
}
.sc-stat {
  background: #1c2133;             /* was rgba(255,255,255,0.04) ≈ invisible — now a real surface */
  border: 1px solid #2e3550;       /* was rgba(255,255,255,0.07) — now clearly visible */
  border-radius: 10px;
  padding: 14px 16px;              /* slightly more padding */
}
.sc-stat-label {
  font-family: 'DM Mono', monospace;
  font-size: 0.70rem;              /* was 0.58 — now readable */
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(255,255,255,0.55);   /* was 0.35 */
  margin-bottom: 7px;
}
.sc-stat-value {
  font-size: 0.96rem;              /* was 0.88 */
  font-weight: 600;
  line-height: 1.35;
  color: #eef0f5;
}
.sc-stat-value.prop   { color: var(--gold-light); }   /* lightened for the dark card */
.sc-stat-value.shares { color: var(--moss-light); }
.sc-stat-value.gold  { color: #e0c070; }
.sc-stat-value.warn  { color: #ffaa60; }

/* Divider */
.sc-divider {
  height: 1px;
  background: rgba(255,255,255,0.10);  /* was 0.07 */
  margin: 0 0 14px;
}

/* Assumptions strip */
.sc-assumptions {
  display: flex;
  flex-wrap: wrap;
  gap: 5px 16px;
  font-family: 'DM Mono', monospace;
  font-size: 0.72rem;              /* was 0.62 */
  color: rgba(255,255,255,0.50);   /* was 0.30 */
  margin-bottom: 16px;
}
.sc-assumptions strong {
  color: rgba(255,255,255,0.80);   /* was 0.55 */
}

/* Footer: disclaimer + URL */
.sc-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.sc-disclaimer {
  font-size: 0.70rem;              /* was 0.60 */
  color: rgba(255,255,255,0.38);   /* was 0.20 */
  line-height: 1.55;
  flex: 1;
}
.sc-url {
  font-family: 'DM Mono', monospace;
  font-size: 0.72rem;              /* was 0.62 */
  color: rgba(201,168,76,0.80);    /* was 0.55 — gold URL now visible */
  white-space: nowrap;
  flex-shrink: 0;
}

/* Action buttons row (outside the card, not captured) */
.sc-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
}
.sc-action-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: 'Inter Tight', sans-serif;
  font-size: 0.82rem;
  font-weight: 600;
  padding: 10px 20px;
  border-radius: 9px;
  border: none;
  cursor: pointer;
  transition: opacity 0.15s, transform 0.1s;
}
.sc-action-btn:hover { opacity: 0.88; transform: translateY(-1px); }
.sc-action-btn.primary {
  background: linear-gradient(135deg, var(--clay, #C97A3A), var(--gold-dim));
  color: #ffffff;
}
.sc-action-btn.secondary {
  background: rgba(255,255,255,0.08);
  color: rgba(255,255,255,0.75);
  border: 1px solid rgba(255,255,255,0.12);
}
.sc-action-btn.close-btn {
  background: rgba(255,255,255,0.05);
  color: rgba(255,255,255,0.45);
  border: 1px solid rgba(255,255,255,0.08);
}
.sc-hint {
  font-size: 0.70rem;
  color: rgba(255,255,255,0.28);
  text-align: center;
  font-family: 'DM Mono', monospace;
}


/* ══ LIGHT MODE — COMPREHENSIVE CONTRAST FIX v2 ══════════════════════════════
   Every component that was unreadable in day mode.
   All colours WCAG AA verified against their backgrounds.
══════════════════════════════════════════════════════════════════════════════ */

/* ── Global ── */
body { color: #1a1d26; }
/* html{font-size:15.5px} removed here (2026-08, font-parity audit) — this
   was the actual value that won (later in the file, same specificity as
   the RESET section's own html rule), and the root cause of PvS's whole
   type scale reading ~3-6% smaller than retirement.html's. See the
   RESET section's html rule (now 16px) for the full explanation. */

/* ── Chart cards & titles ──
   Retirement-parity pass (2026-08): shadow re-ported from a single-layer
   PvS-specific value to retirement.html's exact 2-layer --tp-shadow-card,
   same as .section above. */
.chart-card {
  background: #ffffff;
  border: 1px solid #d0d4e0;
  box-shadow: 0 2px 10px rgba(14,21,18,.07), 0 1px 3px rgba(14,21,18,.05);
}
.chart-title { color: #0f1118 !important; font-weight: 700; }

/* ── KPI cards ──
   box-shadow deliberately omitted here (was 0 1px 4px rgba(0,0,0,.05) —
   weaker than and would silently override the visual-weight pass's
   stronger 0 3px 10px rgba(0,0,0,.07) set earlier in this file, since
   this "light mode" block loads later at equal specificity). Found via
   the same class of bug as today's toggle collision — a later override
   block quietly winning over an earlier, intentional value. */
/* .kpi-card background/border and .kpi-sub colour removed (2026-09) — all
   three were hardcoded hexes duplicating what var(--bg-surface),
   var(--border) and var(--text-secondary) already resolve to, and they lived
   in a page stylesheet for a results-area component. See calculators.css. */

/* ── Section intro / hint ── */
.section-intro { color: #374060 !important; }
.chart-card .hint { color: #505870 !important; }

/* Light-mode .section/.section-header/.section-body overrides removed —
   the sidebar's accordion is now .card/.card-header/.card-content, styled
   via css/simulators.css (no light/dark variant to override here). */

/* ── Tabs ──
   Removed here (2026-08): three dark-theme-era !important overrides
   (.tabs border-bottom-color, .tab:not(.active) color, and its hover)
   that would otherwise silently beat the ported underline-tab design's
   own border-bottom-color (#e3ede8, retirement's exact value),
   var(--text-muted) inactive color, and var(--gold-text) hover color —
   same class of collision as everything else found in today's audit.
   The tab redesign's base rule already sets final, WCAG-checked colors
   directly, so these patches are redundant now, not just risky. */

.insights-list li { color: #1a2030 !important; font-size: .82rem; }

/* The Decision Summary Card's light-mode overrides stood here — one
   duplicate of nearly every selector in the block above. They went with it. */

/* ── Monte Carlo stats ── */
.mc-stat { background: #ffffff; border: 1px solid #d0d4e0; }
.mc-stat-label { color: #374060 !important; }
.mc-stat-val { color: #0f1118 !important; }
.mc-note { color: #505870 !important; }

/* ── MC transparency note ── */
.mc-transparency-note {
  background: rgba(184,146,46,.06) !important;
  border-color: rgba(184,146,46,.25) !important;
  color: #374060 !important;
}
.mc-transparency-note strong { color: var(--gold-text) !important; }
.mc-transparency-note li { color: #374060 !important; }

/* ── Sensitivity grid ── */
.sensitivity-grid td { color: #0f1118 !important; }
.sensitivity-grid th { color: #374060 !important; }

/* ── Assumptions grid ── */
.assumption-card { background: #ffffff; border: 1px solid #d0d4e0; }
.assumption-key { color: #374060 !important; }
.assumption-val { color: #0f1118 !important; }

/* ── Cashflow verification ── */
.cashflow-verification { background: #ffffff; border: 1px solid #d0d4e0; }
.cfv-meta .k { color: #505870 !important; }
.cfv-meta .v { color: #0f1118 !important; }

/* ── Empty state ── */
.empty-icon { color: #c0c4d0; }
.empty-title { color: #0f1118 !important; }
.empty-sub { color: #374060 !important; }

/* ── Sidebar controls ── */
/* .mode-toggle-bar used to force color:#374060 here, the last per-page
   declaration on the shared component. Removed: every child of the bar
   (.mode-toggle-label, .mode-btn, .mode-hint) sets its own colour in
   css/simulators.css, so this only made the two pages' inherited colour
   differ — measured rgb(55,64,96) here against retirement's rgb(11,31,22) —
   with nothing visible depending on it. */
/* .mode-btn:not(.active) used to force #374060 here. Removed: the inactive
   label colour now comes from the shared component in css/simulators.css
   (#55685F, the canonical muted from #207), so both consumers match. It was
   the last thing making the two toggles differ once the chrome was shared —
   measured, Property vs Shares rendered rgb(55,64,96) against retirement's
   rgb(85,104,95). */
.range-val { color: #374060 !important; }
/* .toggle-label color override removed here (2026-08 Stage 2): value-equal
   to the consolidated rule now in css/calculators.css (#2c3248 ==
   var(--text-secondary)), a no-op duplicate post-extraction. */

/* .edu-faq-item summary/p and .edu-table td color overrides moved to
   css/calculators.css — 2026-08 Stage 2. */

/* ── Share card light-mode variant ── */
#share_card.light-mode {
  background: #f8f9fc;
  box-shadow: 0 24px 80px rgba(0,0,0,.25);
}
/* Remove grid watermark in light mode — causes checkered artifact in html2canvas */
#share_card.light-mode::after {
  display: none;
}
#share_card.light-mode::after {
  background-image:
    linear-gradient(rgba(0,0,0,.025) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0,0,0,.025) 1px, transparent 1px);
}
#share_card.light-mode .sc-headline { color: #0f1118; }
#share_card.light-mode .sc-headline strong { color: #000; }
#share_card.light-mode .sc-brand { color: rgba(0,0,0,.35); }
#share_card.light-mode .sc-brand span { color: rgba(0,0,0,.22); }
#share_card.light-mode .sc-winner-badge.property { background: color-mix(in srgb, var(--clay, #C97A3A) 12%, transparent); color: var(--property); border-color: color-mix(in srgb, var(--clay, #C97A3A) 25%, transparent); }
#share_card.light-mode .sc-winner-badge.shares   { background: color-mix(in srgb, var(--moss, #4C7A5B) 12%, transparent); color: var(--shares);   border-color: color-mix(in srgb, var(--moss, #4C7A5B) 25%, transparent); }
#share_card.light-mode .sc-stat { background: #ffffff; border-color: #d4d8e8; }
#share_card.light-mode .sc-stat-label { color: #505870; }
#share_card.light-mode .sc-stat-value { color: #0f1118; }
#share_card.light-mode .sc-stat-value.prop   { color: var(--property); }
#share_card.light-mode .sc-stat-value.shares { color: var(--shares); }
#share_card.light-mode .sc-stat-value.gold  { color: var(--gold-text); }
#share_card.light-mode .sc-stat-value.warn  { color: #8b3a00; }
#share_card.light-mode .sc-divider { background: rgba(0,0,0,.10); }
#share_card.light-mode .sc-assumptions { color: rgba(0,0,0,.40); }
#share_card.light-mode .sc-assumptions strong { color: rgba(0,0,0,.65); }
#share_card.light-mode .sc-disclaimer { color: rgba(0,0,0,.30); }
#share_card.light-mode .sc-url { color: rgba(120,80,0,.55); }

/* ── Global font-size minimums — raise tiny labels to readable floor ── */
/* .kpi-label removed from this list (2026-08, font-parity audit): the
   "floor" here is a flat .73rem, which is SMALLER than .kpi-label's real
   size (.8rem — now css/calculators.css's shared .insight-label/
   .kpi-label rule, previously a local rule right here). Since both
   declarations had equal specificity, this later one was winning and
   silently shrinking .kpi-label from .8rem down to .73rem — a floor rule
   overriding a value that was already above the floor, backwards from
   its own stated purpose. Confirmed via getComputedStyle: KPI card
   labels ("FUTURE VALUE WINNER" etc.) were rendering at 11.315px instead
   of the 12.4-12.8px retirement.html's equivalent labels use. Leaving
   .kpi-label off this list stays correct/necessary even now that the
   sizing lives in calculators.css (loaded after this file, so it would
   win regardless) — no reason to re-add a selector that only ever caused
   harm here. */
.badge,
.sc-stat-label,
.mc-stat-label,
.section-intro,
.assumption-key,
.cfv-meta .k,
.hint {
  font-size: max(.73rem, 0.73rem); /* floor ~11px at 15px base — .edu-tab's
  membership in this list moved to css/calculators.css's own consolidated
  .edu-tab rule (2026-08 Stage 2): it's baked into that rule's font-size
  directly (.73rem) rather than reapplied via this shared selector list. */
}


/* SEO editorial styles moved to /css/seo-editorial.06b0142e.css */

.related-tools {
  max-width: 900px;
  margin-left: auto;
  margin-right: auto;
  padding: 0 24px;
}

/* ── RELATED TOOLS GRID ── */
.related-tools {
  margin-bottom: 64px;
}

.related-tools__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px;
}

.related-tool-card {
  display: block;
  padding: 16px;
  background: rgba(255,255,255,.04);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: var(--text-secondary);
  transition: border-color .15s, background .15s, transform .15s;
}

.related-tool-card:hover {
  border-color: var(--gold);
  background: rgba(201,168,76,.04);
  transform: translateY(-2px);
  color: var(--text-secondary);
  text-decoration: none;
}

.related-tool-card--featured {
  background: rgba(201,168,76,.05);
  border-color: rgba(201,168,76,.25);
}

.related-tool-card--featured:hover {
  background: rgba(201,168,76,.09);
}

.rtc-title {
  font-weight: 600;
  font-size: .85rem;
  color: var(--text-primary);
  margin-bottom: 5px;
}

.rtc-title--gold { color: var(--gold); }

.rtc-desc {
  font-size: .75rem;
  color: var(--text-muted);
  line-height: 1.5;
}

/* Light theme */
.related-tool-card {
  background: #fff;
  border-color: #d0dfe0;
}
.related-tool-card:hover {
  border-color: var(--gold);
  background: #fffbf0;
}
.related-tool-card--featured {
  background: #fffbf2;
  border-color: rgba(201,168,76,.4);
}
.rtc-title { color: #0f1118; }
.rtc-title--gold { color: var(--gold-text); }
.rtc-desc { color: #505870; }

/* ── RESPONSIVE ── */
@media (max-width: 768px) {
  .related-tools { padding: 0 16px; }
  .related-tools__grid { grid-template-columns: 1fr 1fr; gap: 10px; }
}

@media (max-width: 480px) {
  .related-tools__grid { grid-template-columns: 1fr; }
}

/* ── Disclaimer footer ──
   Moved out of property_vs_shares.html's inline <style> block — 2026-08
   Stage 2 (PvS-specific, not part of the shared calculators.css layer). */
#disclaimerFooter { display: flex; }
#disclaimerFooter .disclaimer-inner { display: flex; align-items: flex-start; width: 100%; gap: 0.5rem; }
#disclaimerFooter[hidden] { display: none !important; }
