/* ══════════════════════════════════════════════════════════════════════════
   WaterFax — global design system.

   PHASE A of the global UI migration. The owner-approved prototype
   (waterfax_homepage_partner_and_report_ui) is the visual authority: tokens,
   Inter typography, rounded geometry, soft borders and shadows are taken from
   waterfax.css in that package and are NOT retuned here.

   ── WHAT THIS FILE DELIBERATELY PRESERVES ────────────────────────────────
   Every CLASS NAME the application already uses. The report is rendered by
   render() in index.html from a server view-model, and its rating chips
   (tag-accent / tag-neutral / tag-outline) are chosen in Python
   (server/spike/build_report.py) and passed through consumerView.mjs. A class
   rename here would break report styling from the other side of the product,
   so the contract is honoured and only the LOOK changes. Phase E may revisit
   the report, updating both ends together.

   ── ADDITIONS BEYOND THE PROTOTYPE (owner-approved) ──────────────────────
   1. Keyboard focus states. The prototype ships none; a product cannot be
      operated without them. ~3px ring derived from --red, via :focus-visible
      so pointer users are not shouted at.
   2. Minimum responsive navigation. The prototype declares .mobile-menu but
      ships no drawer. A single accessible disclosure is provided, nothing more.

   Layout for the six non-prototyped screens (invite, verify, checkout,
   generation, compare, account) is DERIVED from these components in later
   phases rather than invented.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── TOKENS ─────────────────────────────────────────────────────────────────
   Prototype values, verbatim. The --color-* aliases below keep the existing
   markup working unchanged: roughly 300 inline style="" attributes in
   index.html reference them, and rewriting those in Phase A would mean
   touching application markup for no visual gain. They are aliases, not a
   second palette -- each points at a prototype token. */
/* ── SELF-HOSTED INTER ──────────────────────────────────────────────────────
   The V3 design authority sets Inter for body and Inter Tight for display, and
   Inter Tight's tighter display face is a real part of the page's character --
   the large hero address especially.

   SELF-HOSTED, not loaded from Google: a paid report must render identically
   offline and in every PDF path, and a third-party font request from the page
   a customer paid for is a privacy cost with no product benefit. These are the
   Latin variable subsets, 93 KB for both, covering every weight the design
   uses. `font-display:swap` means a slow font never blocks the report. */
@font-face{font-family:'Inter';font-style:normal;font-weight:100 900;
  font-display:swap;src:url('inter-var.woff2') format('woff2')}
@font-face{font-family:'Inter Tight';font-style:normal;font-weight:100 900;
  font-display:swap;src:url('inter-tight-var.woff2') format('woff2')}

:root{
  /* ── V3 DESIGN AUTHORITY PALETTE ──────────────────────────────────────
     Values are the design package's own tokens. Status colours are SEMANTIC
     and deliberately separate from the brand red: red never means "bad"
     anywhere in this report, which matters because an absence of records must
     never be coloured as a finding. */
  --red:#E5341D; --red2:#CC2913; --soft:#FDEBE7;
  --ink:#0F1729; --ink-2:#4A5363; --navy:#0F1729; --muted:#6B7382;
  --line:#E7E9EE; --rule-2:#D3D8E0; --bg:#F6F7F9; --white:#FFFFFF;
  --good:#16804A; --good-bg:#E7F5EC;
  --watch:#B25E09; --watch-bg:#FEF2DF;
  --info:#3A4A60; --info-bg:#EEF1F6;
  --lc-1:#1F8A5B; --lc-2:#C69214; --lc-3:#4F6BD0;
  --hero-ink:#FFFFFF; --hero-muted:#B9C1CE; --hero-line:rgba(255,255,255,.14);
  --shadow:0 1px 2px rgba(15,23,41,.05),0 10px 30px rgba(15,23,41,.07);
  --shadow-card:0 12px 32px rgba(15,23,41,.10);

  /* ── TYPOGRAPHY ────────────────────────────────────────────────────────
     SUPERSEDED FINDING: the earlier prototype's CSS named Inter but linked no
     webfont, so system-ui was what actually rendered and was what the owner
     approved. The V3 package links Inter and Inter Tight explicitly, so the
     approved rendering is now the real face. Both are self-hosted above; the
     system stack remains behind them so a failed font load degrades to a sane
     face rather than to Times. */
  --font-display:'Inter Tight','Inter',system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-heading:var(--font-display);
  --font-body:'Inter',system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --font-heading-weight:800;

  /* Geometry: 12-34px rounded, replacing the previous square system. */
  --radius-sm:12px; --radius-md:18px; --radius-lg:22px; --radius-xl:34px;
  --radius-pill:999px;

  --space-2:8px; --space-3:12px; --space-4:16px; --space-6:24px; --space-8:32px;

  /* Focus ring (owner-approved addition). Visible on white, soft-red and navy. */
  --focus-ring:0 0 0 3px rgba(236,48,19,.55);
  --focus-ring-on-dark:0 0 0 3px rgba(255,255,255,.85);
  --focus-offset:2px;

  /* ── COMPATIBILITY ALIASES ──────────────────────────────────────────────
     Existing markup names, remapped onto the prototype palette. */
  --color-bg:var(--white);
  --color-surface:var(--bg);
  --color-text:var(--ink);
  --color-accent:var(--red);
  --color-accent-2:var(--red2);
  --color-accent-100:var(--soft);
  --color-accent-700:var(--red2);
  --color-divider:var(--line);
  --color-neutral-100:#f7f9fc;
  --color-neutral-200:#eef0f4;
  --color-neutral-300:var(--line);
  --color-neutral-500:#93a0b4;
  --color-neutral-700:var(--muted);
  --color-neutral-900:var(--ink);
  --shadow-sm:0 1px 2px rgba(23,32,51,.10);
}

*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--white);color:var(--ink);font-family:var(--font-body);
  line-height:1.5;-webkit-font-smoothing:antialiased}
/* The prototype leaves headings at the browser default (700) and reserves 800+
   for nav, buttons and labels. Forcing 800 here rendered every heading heavier
   than the prototype -- visible as horizontal drift in a 50% overlay, because
   the wider glyphs push each line out even though the box measures the same. */
h1,h2,h3{font-family:var(--font-heading);margin:0;letter-spacing:-.03em;line-height:1.08}
h1{letter-spacing:-.045em}
a{color:var(--red2);text-decoration:none}
a:hover{text-decoration:underline}
button,input,select,textarea{font:inherit}
.hr{border:none;border-top:1px solid var(--line);margin:0}
.hidden{display:none!important}

/* ── FOCUS (owner-approved addition) ────────────────────────────────────────
   :focus-visible so a mouse click does not paint a ring, but every keyboard
   route through the product is traceable. Applied broadly, then specialised
   for dark surfaces where red-on-navy would not carry. */
:focus-visible{outline:none;box-shadow:var(--focus-ring);
  border-radius:var(--radius-sm);outline-offset:var(--focus-offset)}
a:focus-visible,button:focus-visible,summary:focus-visible,
[tabindex]:focus-visible,[role="button"]:focus-visible{
  box-shadow:var(--focus-ring)}
input:focus-visible,select:focus-visible,textarea:focus-visible{
  box-shadow:var(--focus-ring);border-color:var(--red)}
/* Dark takeovers (invite / verify) and the navy/red bands: a red ring on those
   grounds is close to invisible, so the ring inverts. */
.takeover :focus-visible,.cta-band :focus-visible,.ref-box :focus-visible,
.price-box :focus-visible,footer :focus-visible{box-shadow:var(--focus-ring-on-dark)}

/* ── LAYOUT ─────────────────────────────────────────────────────────────────
   The prototype's .container is a WIDTH, with the gutter built into the
   min() rather than added as padding:

       width: min(1180px, calc(100% - 40px));  margin: 0 auto;

   The earlier `max-width:1180px` PLUS 40px of padding produced a 1100px content
   box, so every hero measurement ran 80px narrow -- which is what pushed the
   headline onto five lines, wrapped the lead early, and broke the price row.
   Measured against the rendered prototype, not assumed. */
.wrap{width:min(1180px,calc(100% - 40px));margin:0 auto;padding:0}
section{padding:72px 0 48px}
/* A <section class="wrap"> takes BOTH rules; the vertical rhythm is restated
   here so `padding:0` above cannot erase it. */
section.wrap{padding:72px 0 48px}
.grid2{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:24px}

/* ── NAVIGATION ─────────────────────────────────────────────────────────────*/
/* The bar spans the viewport; its CONTENTS align to the same 1180px column as
   the page body. Stretching the links to the screen edges was what made the
   first attempt read as a generic SaaS header. */
.nav{position:sticky;top:0;z-index:50;background:rgba(255,255,255,.96);
  backdrop-filter:blur(14px);border-bottom:1px solid rgba(231,233,238,.9);
  display:flex;justify-content:space-between;align-items:center;gap:24px;
  min-height:76px;flex-wrap:wrap;row-gap:10px;
  /* The BAR is full width so its rule and blur reach the viewport edges; the
     inline padding pulls the CONTENTS onto the 1180px editorial column. */
  padding:0 max(20px,calc(50% - 590px))}
/* Brand mark + wordmark, from the prototype. The droplet is the :after. */
.nav-brand{display:inline-flex;align-items:center;gap:10px;font-family:var(--font-heading);
  font-weight:800;font-size:24px;letter-spacing:-.03em;cursor:pointer;
  background:none;border:0;padding:0;color:inherit;border-radius:var(--radius-sm)}
.nav-brand .accent{color:var(--red)}
.brand-mark{width:34px;height:34px;border-radius:50%;background:var(--red);
  position:relative;box-shadow:inset 0 0 0 7px #fff;border:5px solid var(--red);flex:none}
.brand-mark:after{content:"";position:absolute;right:-5px;bottom:-1px;width:12px;
  height:16px;background:var(--red);border-radius:60% 60% 65% 35%;transform:rotate(32deg)}
.navlinks{display:flex;align-items:center;gap:24px;font-size:14px;font-weight:700;margin-left:auto}
/* :not(.btn) so the CTA inside the link group keeps its filled treatment --
   without it the nav's link styling stripped the red button back to plain text. */
.navlinks a:not(.btn),.navlinks button:not(.btn){color:#455067;background:none;
  border:0;padding:8px 4px;cursor:pointer;border-radius:var(--radius-sm);font-weight:700}
.navlinks a:not(.btn):hover,.navlinks button:not(.btn):hover{color:var(--red);text-decoration:none}

/* Mobile disclosure (owner-approved addition; prototype declares the class
   only). One control, one panel, keyboard operable, closes predictably. */
.mobile-menu{display:none;align-items:center;justify-content:center;
  min-height:44px;min-width:44px;padding:0 14px;border:1px solid var(--line);
  background:var(--white);border-radius:var(--radius-sm);cursor:pointer;
  font-weight:800;color:var(--ink)}
.nav-panel{display:none}
.nav-panel.open{display:flex;flex-direction:column;gap:4px;width:100%;
  padding:12px 0 6px;border-top:1px solid var(--line)}
.nav-panel a,.nav-panel button{display:block;width:100%;text-align:left;
  padding:13px 6px;font-size:15px;font-weight:700;color:#455067;
  background:none;border:0;cursor:pointer;border-radius:var(--radius-sm)}

/* Footer. Carries Legal, which the prototype's own footer also does, so it is
   a route rather than a demotion. */
.site-footer{border-top:1px solid var(--line);background:var(--white);
  padding:28px 0;margin-top:8px}
.site-footer-inner{display:flex;justify-content:space-between;align-items:center;
  gap:20px;flex-wrap:wrap;font-size:13px;color:var(--muted)}
.site-footer-links{display:flex;gap:22px;flex-wrap:wrap;font-weight:700}
.site-footer-links a{color:#455067;border-radius:var(--radius-sm)}
.site-footer-links a:hover{color:var(--red);text-decoration:none}

/* ── BUTTONS ────────────────────────────────────────────────────────────────*/
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  min-height:46px;padding:0 20px;border-radius:var(--radius-sm);
  border:1px solid var(--line);background:var(--white);color:var(--ink);
  font-family:var(--font-body);font-weight:800;font-size:14px;
  cursor:pointer;transition:.2s ease}
.btn:hover{background:var(--bg);transform:translateY(-1px)}
.btn-primary{background:var(--red);border-color:var(--red);color:#fff;
  box-shadow:0 10px 20px rgba(236,48,19,.18)}
.btn-primary:hover{background:var(--red2);border-color:var(--red2)}
.btn-block{width:100%}
/* The prototype's secondary variant. The base .btn is already white-on-border,
   so this exists to make the markup say which role a button plays rather than
   relying on the absence of .btn-primary. */
.btn-secondary{background:#fff;border-color:var(--line)}
.btn:disabled{opacity:.45;cursor:not-allowed;transform:none;box-shadow:none}

/* ── FORMS ──────────────────────────────────────────────────────────────────*/
.input,.field input,.field select,.field textarea{
  width:100%;border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:14px 15px;background:var(--white);color:var(--ink);
  font-family:var(--font-body);font-size:15px;outline:none}
.input:hover{border-color:#cfd5df}
.field{display:grid;gap:8px;margin-bottom:18px}
.field label{font-size:13px;font-weight:850;color:#455067}
.field textarea{min-height:118px;resize:vertical}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.form-card{background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius-lg);padding:30px;box-shadow:var(--shadow)}

/* ── CARDS / PANELS ─────────────────────────────────────────────────────────*/
.card{background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius-md);padding:24px}
.panel{background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius-lg);padding:24px}
.partner-card{background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius-lg);padding:28px;box-shadow:var(--shadow)}
.privacy-box{background:#f7f9fc;border:1px solid var(--line);
  border-radius:var(--radius-md);padding:18px;margin-top:18px}
.empty{border:1px dashed var(--line);border-radius:var(--radius-md);padding:22px;
  text-align:center;color:var(--muted);font-size:14px}

/* ── STATUS TREATMENTS ──────────────────────────────────────────────────────
   Every status carries TEXT. Colour is reinforcement, never the sole carrier
   of meaning -- an accessibility requirement and, for commission state, a
   truthfulness one. */
.tag{display:inline-block;font-size:11.5px;font-weight:800;padding:4px 10px;
  border:1px solid var(--line);border-radius:var(--radius-pill);white-space:nowrap}
.tag-accent{background:var(--soft);border-color:#ffd4ca;color:var(--red2)}
.tag-neutral{background:var(--color-neutral-200);border-color:var(--line);color:var(--muted)}
.tag-outline{background:transparent;border-color:currentColor}
.status-pill{display:inline-flex;align-items:center;gap:8px;border-radius:var(--radius-pill);
  padding:8px 12px;font-size:13px;font-weight:900}
.status-active{background:#e9f8f0;color:#16744d}
.status-pending{background:#fff3d8;color:#8a6200}
.status-reversed{background:#fff0ed;color:#a42a17}
.err{border:1px solid #ffd4ca;background:var(--soft);color:#7a2418;
  border-radius:var(--radius-md);padding:14px;font-size:14px}

/* ── BANNER ─────────────────────────────────────────────────────────────────*/
.banner{background:var(--navy);color:#d6deea;font-size:12.5px;
  padding:9px clamp(20px,5vw,40px);display:flex;gap:18px;flex-wrap:wrap;align-items:center}
.banner b{color:#ffb6a8}

/* ══ ENTRY / IDENTITY TAKEOVERS (Phase B) ═══════════════════════════════════
   The invite gate and email verification. No prototype page exists for either,
   so they are DERIVED from the approved system rather than invented: the navy
   surface is --navy, the accent is the same red, the container arithmetic is
   the approved nav's, the eyebrow/h1/lead hierarchy is the homepage's, and the
   buttons and fields are the shared components at their existing geometry.

   These were two duplicated blocks of inline styles built on the retired
   square-corner tokens. One component now serves both.
   ═══════════════════════════════════════════════════════════════════════════ */
.takeover{min-height:100vh;display:flex;flex-direction:column;position:relative;
  overflow:hidden;background:var(--navy);color:#fff}
/* One soft red bloom, echoing the homepage hero's radial wash rather than the
   previous hard 420px square. */
.takeover:before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(circle at 88% 6%,rgba(236,48,19,.32),transparent 44%)}
.takeover-nav{position:relative;z-index:1;display:flex;justify-content:space-between;
  align-items:center;gap:16px;min-height:76px;padding:0 max(20px,calc(50% - 590px))}
.takeover-body{position:relative;z-index:1;flex:1;display:flex;align-items:center;
  padding:20px max(20px,calc(50% - 590px)) 72px}
.takeover-inner{width:100%;max-width:640px}
.takeover .eyebrow{color:#ff8a73;margin-bottom:18px}
.takeover h1{font-size:clamp(40px,6.5vw,76px);line-height:1.02;letter-spacing:-.045em;margin:0}
.takeover .lead{color:rgba(255,255,255,.78);max-width:56ch;margin:22px 0 0;font-size:18px}
.takeover-foot{position:relative;z-index:1;border-top:1px solid rgba(255,255,255,.18);
  padding:20px max(20px,calc(50% - 590px));font-size:12.5px;color:rgba(255,255,255,.6);
  display:flex;justify-content:space-between;flex-wrap:wrap;gap:12px}
.takeover-foot a{color:rgba(255,255,255,.78)}
.takeover-foot a:hover{color:#fff}

/* Field group. The label is a real <label for>, so it is announced rather than
   sitting above the input as decorative text. */
.takeover-field{margin-top:34px;max-width:460px}
.takeover-field>label{display:block;font-size:12px;letter-spacing:.06em;
  text-transform:uppercase;color:rgba(255,255,255,.65);margin-bottom:10px}
.takeover-row{display:flex;gap:10px}
.takeover-row .input{flex:1;min-width:0;background:rgba(255,255,255,.08);
  border-color:rgba(255,255,255,.28);color:#fff}
.takeover-row .input::placeholder{color:rgba(255,255,255,.45)}
.takeover-note{font-size:12.5px;color:rgba(255,255,255,.6);margin:14px 0 0;max-width:52ch}
.takeover-err{font-size:13px;color:#ffb6a8;margin:10px 0 0}
.takeover .tag-accent{background:rgba(236,48,19,.18);
  border-color:rgba(255,138,115,.5);color:#ffb6a8}
/* The 6-digit code reads as digits, not prose. */
.code-input{letter-spacing:.3em;font-size:20px;font-variant-numeric:tabular-nums}
@media(max-width:620px){
  /* The approved homepage narrows its gutter to 12px at this breakpoint, so
     the takeovers follow rather than sitting 8px further in. */
  .takeover-nav,.takeover-body,.takeover-foot{padding-left:12px;padding-right:12px}
  .takeover-row{flex-direction:column}
  .takeover-row .btn{width:100%}
  .takeover h1{font-size:38px}
  .takeover .lead{font-size:16px}
}

/* ══ PURCHASE JOURNEY (Phase C) ═════════════════════════════════════════════
   Search suggestions, the confirmed-property card, checkout and the generation
   state. No prototype page covers these, so each is built from the approved
   components: .card geometry, the .search-box radius, the approved button and
   field, and the homepage's section rhythm.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Address suggestions. Anchored under the search box and carrying its radius
   and shadow, so the pair reads as one control. */
.sugg-list{position:absolute;left:0;right:0;top:calc(100% + 10px);z-index:20;
  background:#fff;border:1px solid var(--line);border-radius:var(--radius-sm);
  box-shadow:var(--shadow);max-height:280px;overflow:auto;padding:6px}
.sugrow{padding:11px 12px;cursor:pointer;font-size:14.5px;border-radius:8px}
.sugrow+.sugrow{margin-top:2px}
.sugrow:hover{background:var(--bg)}
/* Keyboard highlight. aria-selected is the state, so the styling follows the
   semantics rather than a separate class. */
.sugrow[aria-selected="true"]{background:var(--soft);color:var(--red2);font-weight:700}
/* Required Google Places credit, shown wherever suggestions appear without a
   Google map beside them. Quiet, but never hidden: an attribution the reader
   cannot see does not satisfy the term that requires it. Not a .sugrow, so it
   is never selectable and can never end up in the address field. */
.sug-credit{padding:7px 12px 4px;font-size:11px;color:var(--muted);
  text-align:right;letter-spacing:.02em;pointer-events:none;user-select:none}

/* Confirmed property. A quiet result card, not a second call to action. */
#addrOk{border-radius:var(--radius-md);box-shadow:var(--shadow);
  border-color:var(--line);padding:22px}

/* ── CHECKOUT: THE PURCHASE COMPOSITION (B + A) ─────────────────────────────
   Option B's structure with Option A's payment treatment. One bordered frame
   holds property context and payment, so the two stop reading as unrelated
   applications. The payment track is wider: paying is the active task, and the
   context must orient without competing.
   ─────────────────────────────────────────────────────────────────────────── */
.buy{display:grid;grid-template-columns:minmax(0,.8fr) minmax(0,1.2fr);
  border:1px solid var(--line);border-radius:var(--radius-lg);overflow:hidden;
  box-shadow:var(--shadow);background:#fff}
.buy-context{background:var(--bg);border-right:1px solid var(--line);padding:28px}
.buy-context .eyebrow{margin-bottom:14px}
.buy-addr{font-size:19px;font-weight:800;line-height:1.3;letter-spacing:-.02em;
  margin:0;color:var(--navy)}
.buy-meta{font-size:13px;color:var(--muted);margin:8px 0 0;line-height:1.5}

.buy-order{margin-top:22px;padding-top:18px;border-top:1px solid var(--line)}
.buy-line{display:flex;justify-content:space-between;gap:12px;font-size:15px;padding:6px 0}
.buy-total{font-size:18px;font-weight:800;color:var(--navy);
  padding-top:12px;margin-top:6px;border-top:1px solid var(--line)}
.buy-priceerr{font-size:13px;color:var(--red2);margin:10px 0 0}

.buy-codes{margin-top:22px;padding-top:18px;border-top:1px solid var(--line)}
.buy-codes label{display:block;font-size:12px;text-transform:uppercase;
  letter-spacing:.08em;color:var(--muted);font-weight:800}
.buy-coderow{display:flex;gap:10px;margin-top:10px}
.buy-coderow .input{flex:1;min-width:0}
.buy-hint{font-size:12px;color:var(--muted);margin:6px 0 0}
.buy-msg{font-size:13px;margin:8px 0 0}

/* Option A's payment side: white, calm, generous. Blocks are separated by
   whitespace and a hairline rather than by nested cards, so the Stripe frame
   sits in the page instead of in a box inside a box. */
.buy-pay{padding:28px;background:#fff}
.buy-block+.buy-block{margin-top:22px;padding-top:22px;border-top:1px solid var(--line)}
.buy-block-label{font-size:12px;text-transform:uppercase;letter-spacing:.08em;
  color:var(--muted);font-weight:800;margin-bottom:12px}
.buy-payerr{font-size:13px;color:var(--red2);margin:10px 0 0}
.buy-secure{display:flex;align-items:flex-start;gap:8px;font-size:12.5px;
  color:var(--muted);margin:12px 0 0;line-height:1.5}
.buy-secure svg{flex:none;margin-top:2px}

@media(max-width:900px){
  /* Context first, then payment: the customer should reach the fields quickly,
     so the context panel stays compact rather than filling the first screen. */
  .buy{grid-template-columns:1fr}
  .buy-context{border-right:0;border-bottom:1px solid var(--line);padding:22px}
  .buy-pay{padding:22px}
  .buy-addr{font-size:18px}
}
@media(max-width:620px){
  .buy-coderow{flex-direction:column}
  .buy-coderow .btn{width:100%}
}

/* Generation. The wait is the screen, so it is centred and unhurried. */
#s-gen .bar{height:8px;border-radius:var(--radius-pill);overflow:hidden}
#s-gen .stages{margin-top:26px}

/* ══ REPORT (Phase E) ═══════════════════════════════════════════════════════
   sample-report.html is the visual authority. Components are ported from it,
   with three deliberate departures documented at the end of this block.

   ── WHAT MUST NOT CHANGE ────────────────────────────────────────────────
   .tag-accent / .tag-neutral / .tag-outline are chosen in PYTHON
   (build_report.py) and travel through consumerView.mjs into class= on every
   check chip. They are also baked into ALREADY-STORED immutable artifacts, so
   a rename would unstyle reports customers have already bought. They stay live
   selectors forever; below they are simply restyled to match the prototype's
   state pills.

   .bar, .months, .chartblock and .attribution are load-bearing for the print
   stylesheet and its tests. Restyled, never renamed.
   ═══════════════════════════════════════════════════════════════════════════ */

/* The sheet. Nested INSIDE #s-report so the print rule
   `body > *:not(#s-report):not(#s-compare)` still finds it. */
/* The paper needs air above it. padding-top was 0, so the sheet butted
   straight into the navigation with no separation -- the report looked pinned
   to the header rather than sitting on a page. */
#rep{background:#f4f6f9;padding:22px 0 8px}

/* ── REPORT TOOLBAR ──────────────────────────────────────────────────────────
   Above the paper, never on it: these are actions for the reader, not part of
   the document, so they carry .no-print and sit outside .report-paper. */
#rep .report-toolbar{display:flex;justify-content:space-between;align-items:center;
  gap:16px;flex-wrap:wrap;margin-bottom:16px}
#rep .report-toolbar-left{display:flex;align-items:center;gap:12px}
#rep .report-toolbar-actions{display:flex;gap:10px;flex-wrap:wrap}
@media(max-width:640px){
  /* Stacked, and the primary action stays full width so it is not a small
     target on a phone. */
  #rep .report-toolbar{flex-direction:column;align-items:stretch}
  #rep .report-toolbar-actions{flex-direction:column}
  #rep .report-toolbar .btn{width:100%;justify-content:center}
}
.report-paper{background:#fff;border:1px solid #e3e7ee;border-radius:24px;
  box-shadow:0 30px 90px rgba(22,32,51,.12);overflow:hidden}

/* Cover: photo-backed hero with a white gradient so the copy stays legible.

   THE COVER IS SIZED BY ITS CONTENT, NOT BY A FIXED NUMBER. The score panel is
   absolutely positioned against the cover's bottom edge, so a fixed min-height
   silently clips it whenever the panel grows -- which is exactly what happened
   when the panel gained the prototype's score summary: 501px of panel inside a
   420px cover, overflowing 112px past the top and cutting off the score itself.
   The grid below makes the cover at least as tall as the panel it contains, so
   the panel can never outgrow its own frame again. */
.report-cover{position:relative;display:grid;align-content:start;
  /* RESPONSIVE BY CONSTRUCTION, not by a later override. A fixed 340px second
     column survived into a 390px viewport and pushed the score panel's own
     figures off-screen (measured: panel right edge at 464px in a 390px window).
     auto-fit + minmax collapses the two columns to one as soon as the copy
     column cannot hold its minimum, so no breakpoint has to remember to undo
     it. */
  /* MOBILE-FIRST, so nothing has to remember to undo a desktop column. One
     column by default; the prototype's 340px panel column is opted into only
     where there is room for it (rule below). The reverse arrangement put the
     panel's own figures off-screen at 390px. */
  grid-template-columns:1fr;
  column-gap:34px;row-gap:20px;
  min-height:420px;padding:44px 48px;
  border-bottom:1px solid var(--line);
  background:linear-gradient(90deg,rgba(255,255,255,.98) 0%,rgba(255,255,255,.93) 38%,
             rgba(255,255,255,.36) 62%,rgba(255,255,255,.08) 100%),
             url('waterfax_house_hero.png') right center/cover no-repeat}
/* ── THE ACTUAL HOUSE, IN THE SAME COMPOSITION ──────────────────────────────
   The photograph replaces the stock image as the cover's background layer and
   inherits the identical white-to-transparent gradient: opaque behind the
   address on the left, the property visible on the right. The treatment is the
   design; only the photograph changes.

   object-position is centre-right (68%) rather than centre: a street-level
   frame puts the façade off-centre, and a plain centre crop tends to land on
   road and sky. This keeps the building in the half of the cover the gradient
   actually reveals.

   No dark overlay is added anywhere -- the left side stays white so the address
   is readable against it, which is the whole point of the treatment. */
.report-cover.has-photo{
  /* ── DARK LEFT, PHOTOGRAPH RIGHT ──────────────────────────────────────
     The white wash carried the address well on a bright facade and washed a
     dark one out entirely -- on 12002 Tregenning Pl the house all but
     disappeared. A white scrim has to get heavier as the photograph gets
     lighter, so it can be tuned for one property and wrong for the next.

     Inverting it removes that dependency: white text over a dark navy field
     holds its contrast whatever the imagery does underneath, so the scrim can
     stay LIGHTER and the house stays visible.

     TUNED DOWN after review -- the first pass held ~.90 out to 46% width and
     only cleared at 92%, which read as a text panel over an almost-black
     photograph rather than a photograph with readable text on it. It now
     starts at .74, is down to ~.22 by half-width and is GONE by 64%, so the
     middle of the hero shows the house and the right side is untouched
     imagery. The text sits in the leftmost third, where the scrim is still
     heavy enough to carry it.

     The score panel is rgba(255,255,255,.96), so it sits above this and is
     unaffected either way. */
  background:linear-gradient(90deg,
             rgba(12,22,38,.74) 0%, rgba(12,22,38,.52) 30%,
             rgba(12,22,38,.22) 50%, rgba(12,22,38,0) 64%),
             var(--hero-photo) 68% center/cover no-repeat;
}
/* Text on the darkened field. The address is the one thing that must never be
   in doubt, so it goes pure white; the meta pills swap their light background
   for a translucent dark one with a hairline, rather than punching white
   rectangles through the gradient. */
.report-cover.has-photo h1{color:#FFFFFF}
.report-cover.has-photo .report-brandline strong{color:#FFFFFF}
.report-cover.has-photo .report-meta{color:rgba(255,255,255,.82)}
.report-cover.has-photo .report-meta span{
  background:rgba(255,255,255,.10);border-color:rgba(255,255,255,.26);
  color:rgba(255,255,255,.92)}
/* WATERFAX HOME REPORT stays WaterFax red -- it is the brand accent and reads
   correctly against navy. */
.report-cover.has-photo .report-label{color:var(--red)}
/* The mark needs NO override: it is already a red disc with a white inset ring
   and a red droplet, which reads correctly on navy. Recolouring its :after
   would have repainted the droplet white -- a different logo, not a dark-mode
   one. */
/* Required provider credit. Readable, but deliberately quiet: it sits in the
   photograph's own corner and never competes with the report title. */
.report-cover-credit{position:absolute;right:10px;bottom:8px;z-index:3;
  padding:2px 7px;border-radius:4px;font-size:11px;line-height:1.4;
  color:#fff;background:rgba(0,0,0,.42)}
/* On a narrow screen the cover collapses to one column and the photograph would
   sit behind the whole address. The gradient is turned vertical there so the
   text keeps a white bed and the picture reads underneath it. */
/* ── THE FADE FOLLOWS THE LAYOUT, NOT AN ARBITRARY BREAKPOINT ─────────────
   The cover collapses to ONE column below 901px (rule further down), but this
   was guarded at 640px -- so between 641 and 900 the copy sat in a single
   column while the gradient was still horizontal, putting the address over the
   bright right-hand side of the photograph. Measured at 768px: white text on a
   0.92-luminance field, a contrast ratio of 1.1:1, effectively invisible.

   Matching this to 900px keeps the two in step: wherever the cover is one
   column, the fade runs top-to-bottom. */
@media(max-width:900px){
  /* One column: the fade runs top-to-bottom so the copy keeps a dark bed and
     the photograph reads beneath it, rather than the address sitting over the
     middle of the house. */
  .report-cover.has-photo{
    /* Lightened in step with the desktop rule. One column stacks the copy ABOVE
       the photograph rather than beside it, so the scrim has to carry further
       down the frame -- but it still clears entirely, leaving the lower part of
       the hero as untouched imagery. */
    background:linear-gradient(180deg,
               rgba(12,22,38,.80) 0%, rgba(12,22,38,.62) 34%,
               rgba(12,22,38,.28) 56%, rgba(12,22,38,0) 74%),
               var(--hero-photo) center 38%/cover no-repeat;
  }
}
.report-cover-inner{max-width:620px;position:relative;z-index:2;grid-column:1}
/* Two columns only where the copy and the panel genuinely both fit. */
@media(min-width:901px){
  .report-cover{grid-template-columns:minmax(0,1fr) 340px}
}
/* The panel occupies a real grid cell, so it contributes its height to the
   cover instead of hanging off it. It keeps its floating look by sitting in the
   second column and pulling itself down to the prototype's optical position. */
.report-cover .report-score-panel{position:relative;grid-column:auto;
  right:auto;bottom:auto;align-self:end;width:340px;max-width:100%;margin-top:auto}
.report-brandline{display:flex;align-items:center;gap:10px;margin-bottom:44px}
.report-brandline strong{font-size:21px;letter-spacing:-.03em}
.report-label{color:var(--red);font-size:12px;font-weight:900;letter-spacing:.12em;
  text-transform:uppercase}
.report-cover h1{font-size:clamp(34px,4.4vw,54px);line-height:1;letter-spacing:-.05em;
  margin:10px 0 14px;color:var(--ink)}
.report-meta{display:flex;gap:12px;flex-wrap:wrap;color:var(--muted);font-size:13px}
.report-meta span{background:rgba(255,255,255,.85);border:1px solid var(--line);
  border-radius:var(--radius-pill);padding:8px 11px}

/* Sections: 42/48 rhythm, hairline separated, kicker + heading + lede. */
.report-section{padding:42px 48px;border-bottom:1px solid var(--line)}
.report-section:last-child{border-bottom:0}
.report-section-head{display:flex;justify-content:space-between;align-items:flex-end;
  gap:22px;margin-bottom:26px;flex-wrap:wrap}
.report-section-head h2{font-size:clamp(24px,2.6vw,32px);margin:6px 0 0;letter-spacing:-.03em}
.report-section-head p{max-width:560px;color:var(--muted);margin:0}

.report-disclaimer{background:#f8fafc;border:1px solid var(--line);
  border-radius:var(--radius-md);padding:18px;color:#526176;font-size:13px}
.report-footer{padding:22px 48px 30px;color:var(--muted);font-size:12px}
.report-fact{border:1px solid var(--line);border-radius:14px;padding:16px}
.report-fact span{display:block;font-size:12px;color:var(--muted);text-transform:uppercase;
  letter-spacing:.06em;font-weight:800}
.report-fact strong{display:block;margin-top:6px}
.report-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px}

@media(max-width:900px){
  .report-cover{padding:32px 22px;min-height:0;row-gap:20px;
    background:linear-gradient(180deg,rgba(255,255,255,.97),rgba(255,255,255,.88)),
               url('waterfax_house_hero.png') center/cover no-repeat}
  .report-section{padding:30px 22px}
  .report-footer{padding:20px 22px 26px}
  .report-section-head{align-items:flex-start}
}

/* ── SCORE (E2) ────────────────────────────────────────────────────────────
   The prototype floats a glass panel over the cover. Kept as a panel, but the
   .bar STAYS: it is required by the print stylesheet and its test, and it
   carries meaning that a number alone does not. The prototype has no bar. */
.report-score-panel{position:absolute;right:34px;bottom:34px;width:min(340px,44%);
  background:rgba(255,255,255,.96);backdrop-filter:blur(10px);
  border:1px solid rgba(29,41,57,.12);border-radius:22px;padding:22px;
  box-shadow:0 22px 50px rgba(22,32,51,.16);z-index:2}
/* The panel also carries .scorebox (the print contract and the score tests pin
   that class), and .scorebox is display:flex. That made the score head, the bar
   and the summary siblings in a ROW: at 390px the bar was squeezed to 5px and
   sat at the panel's right edge. The panel owns its own stacking. */
.report-score-panel.scorebox{display:block;align-items:initial;gap:0}
.report-score-head{display:flex;align-items:flex-start;justify-content:space-between;gap:15px}
.report-score-number{font-size:58px;line-height:.9;font-weight:900;color:var(--red);
  letter-spacing:-.06em;font-variant-numeric:tabular-nums}
.report-score-number small{font-size:18px;color:var(--muted);font-weight:800}
.report-score-caption{font-size:13px;color:var(--muted);margin-top:7px}
/* .scorebox is the FLOW fallback used when there is no cover photo, and the
   element the print stylesheet targets. Restyled, never renamed. */
#rep .scorebox{border:1px solid var(--line);border-radius:var(--radius-lg);padding:24px;
  box-shadow:var(--shadow);gap:22px}

/* ── EVIDENCE CARDS (E3) ───────────────────────────────────────────────────
   .checks/.check are the CLASS CONTRACT emitted by render(); the prototype's
   .evidence-card treatment is applied to them rather than replacing them. */
#rep .checks{gap:18px}
#rep .check{border-radius:18px;padding:22px}
#rep .check h3{font-size:19px;margin:0 0 6px}
.evidence-stat{font-size:32px;font-weight:900;color:var(--navy);letter-spacing:-.04em;
  margin:14px 0 4px;font-variant-numeric:tabular-nums}
.evidence-caption{font-size:12px;color:var(--muted)}

/* STATE PILLS. The prototype's vocabulary, mapped onto the Python-chosen
   classes so build_report.py and every stored artifact keep working. Renaming
   these would unstyle reports that have already been bought. */
/* SCOPED TO #rep. Restyling .tag globally changed the invite gate's "Invite
   only" chip, which is an approved Phase B surface -- shared CSS bleeding into
   a screen this phase is not allowed to touch. The report's state vocabulary
   therefore applies only inside the report. */
#rep .tag-accent{background:#eaf8f0;border-color:#cdebd9;color:#17744e}   /* favourable */
#rep .tag-neutral{background:#eef1f5;border-color:var(--line);color:#69778a} /* neutral / unknown */
#rep .tag-outline{background:#fff4dc;border-color:#f2dfb0;color:#8a6200}   /* watch */
#rep .tag{font-size:12px;font-weight:900;border-radius:var(--radius-pill);padding:7px 10px}

/* ── CHART (E3) ────────────────────────────────────────────────────────────
   The month chart keeps .chartblock/.months/.m/.mlabels: all four are pinned by
   tests, the print stylesheet preserves their ink, and the existing 12-column
   bar chart is the correct shape for 12 monthly values. The prototype's SVG
   line chart would be a different chart of the same data. Ruled paper only. */
#rep .chartblock{background:linear-gradient(180deg,rgba(236,48,19,.04),rgba(236,48,19,0)),
  repeating-linear-gradient(0deg,#fff 0,#fff 31px,#eef1f5 32px);
  border:1px solid var(--line);border-radius:14px;padding:16px 16px 10px;margin-top:14px}
#rep .months{height:130px;gap:6px}
#rep .months .m{border-radius:5px 5px 0 0}
#rep .mlabels{font-size:10.5px}

/* ── SOURCES / ATTRIBUTION (E4) ────────────────────────────────────────────
   .attribution is the anchor for nine assertions and five print rules. It is
   restyled toward the prototype's licence box and NEVER renamed. */
#rep .attribution{background:#fff7f4;border:1px solid #ffd8cf;border-radius:var(--radius-md);
  padding:18px;margin-top:22px;color:#526176;font-size:12.5px}
#rep .attribution a{color:var(--red2)}

@media(max-width:900px){
  /* The selector must match the desktop rule's specificity
     (.report-cover .report-score-panel), or the 340px desktop column survives
     into a 390px viewport and the panel's own figures are cut off the screen.
     Measured: the summary values sat past the right edge at 390px. */
  .report-cover .report-score-panel,.report-score-panel{position:static;width:auto;
    margin-top:22px;backdrop-filter:none;box-shadow:none;border-radius:var(--radius-md)}
  #rep .checks{grid-template-columns:1fr}
}

/* ── EXECUTIVE SUMMARY + CONDENSED FINDINGS (owner UAT rework) ─────────────
   The prototype leads with a summary and a scannable list of the major areas;
   the old report buried its conclusion under nine sequential sections. Ported
   from sample-report.html. Scoped to #rep so nothing reaches an approved
   surface -- the .tag bleed showed why that matters. */
#rep .report-summary-grid{display:grid;grid-template-columns:1.1fr .9fr;gap:24px}
#rep .report-callout{border:1px solid var(--line);border-radius:18px;padding:24px;background:#fff}
#rep .report-callout-red{background:linear-gradient(180deg,#fff7f4,#fff);border-color:#ffd4ca}
#rep .report-callout h3{margin:0 0 8px;font-size:20px}
#rep .report-callout p{margin:0;color:var(--muted)}
/* ── EXECUTIVE SUMMARY ───────────────────────────────────────────────────────
   Colour-coded by TOPIC -- water blue, growth green, heat amber -- so four
   cards are distinguishable at a glance. The hue is decoration and says
   nothing about the finding: the rating still carries the judgement and the
   state pill still carries the evidence state.

   Spacing is deliberately tighter than the report's default 42/48 rhythm. This
   section is a summary, and generic section padding made it scroll like a
   chapter. */
#rep .exec-section{padding:30px 34px}
#rep .exec-section .report-section-head{margin-bottom:18px}

#rep .callout-head{display:flex;align-items:center;gap:13px;margin-bottom:8px}
#rep .callout-head h3{margin:0;font-size:21px;letter-spacing:-.02em}
#rep .callout-icon{width:44px;height:44px;border-radius:50%;flex:none;
  display:grid;place-items:center}
#rep .callout-icon svg{width:22px;height:22px}
#rep .callout-icon.good{background:var(--soft);color:var(--red)}
#rep .callout-icon.na{background:#eef1f5;color:#69778a}
#rep .report-callout{padding:20px 22px}
#rep .report-callout p{font-size:14px;line-height:1.55}
#rep .callout-gap{font-weight:700;color:var(--color-text);margin-bottom:6px}
#rep .callout-note{display:flex;gap:10px;align-items:flex-start;margin-top:14px;
  padding:12px 14px;border-radius:var(--radius-md);background:var(--bg);
  border:1px solid var(--line);font-size:13px;line-height:1.5;color:var(--muted)}
#rep .callout-note-icon{flex:none;color:#8ea0b8;margin-top:1px}
#rep .callout-note-icon svg{width:17px;height:17px}

/* Three figures, in one panel rather than three floating boxes. */
#rep .metric-row{display:grid;grid-template-columns:repeat(3,1fr);margin-top:16px;
  background:#fff;border:1px solid var(--line);border-radius:var(--radius-md);
  overflow:hidden}
#rep .metric{display:flex;align-items:flex-start;gap:10px;padding:14px 14px;
  border-left:1px solid var(--line)}
#rep .metric:first-child{border-left:0}
#rep .metric-icon{width:38px;height:38px;border-radius:50%;flex:none;
  display:grid;place-items:center}
#rep .metric-icon svg{width:20px;height:20px}
#rep .metric-body{min-width:0}
/* The figure leads; the unit rides beside it at label size. */
#rep .metric-stat{display:block;font-size:22px;font-weight:800;letter-spacing:-.035em;
  line-height:1.05}
#rep .metric-stat i{font-style:normal;font-size:13px;font-weight:700;margin-left:3px;
  letter-spacing:0}
#rep .metric-cap{display:block;font-size:11.5px;color:var(--muted);margin-top:4px;
  line-height:1.35}

/* Group cards: icon in its own column, content beside it. */
#rep .report-key-list{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:14px}
#rep .report-key{display:flex;gap:14px;align-items:flex-start;
  border:1px solid var(--line);border-radius:var(--radius-lg);
  padding:18px 20px;background:#fff;border-top:1px solid var(--line)}
#rep .report-key-icon{width:52px;height:52px;border-radius:50%;flex:none;
  display:grid;place-items:center;font-weight:400}
#rep .report-key-icon svg{width:26px;height:26px}
#rep .report-key-body{flex:1;min-width:0}
#rep .report-key-head{display:flex;align-items:center;gap:12px;justify-content:space-between}
#rep .report-key-head strong{font-size:16px;letter-spacing:-.015em}
#rep .report-key-stat{font-size:30px;font-weight:800;letter-spacing:-.04em;
  line-height:1.05;margin:8px 0 0}
#rep .report-key-stat i{font-style:normal;font-size:16px;font-weight:700;margin-left:4px;
  letter-spacing:0}
#rep .report-key-cap{font-size:12.5px;color:var(--muted);margin-top:3px}
#rep .report-key p{margin:9px 0 0;font-size:13.5px;line-height:1.5;color:var(--muted)}

/* ── TOPIC HUES ─────────────────────────────────────────────────────────────
   One family per subject. The tinted disc and the figure share it, so the card
   reads as a unit. */
#rep .hue-blue   .report-key-icon,#rep .hue-blue   .metric-icon{background:#e8f1fc;color:#1f6fd0}
#rep .hue-blue   .report-key-stat,#rep .hue-blue   .metric-stat{color:#1f6fd0}
#rep .hue-green  .report-key-icon,#rep .hue-green  .metric-icon{background:#e7f6ec;color:#1f8f5f}
#rep .hue-green  .report-key-stat,#rep .hue-green  .metric-stat{color:#1f8f5f}
#rep .hue-amber  .report-key-icon,#rep .hue-amber  .metric-icon{background:#fdf0dc;color:#e07b1a}
#rep .hue-amber  .report-key-stat,#rep .hue-amber  .metric-stat{color:#e07b1a}
#rep .hue-forest .report-key-icon,#rep .hue-forest .metric-icon{background:#e6f4e9;color:#2f8f4e}
#rep .hue-forest .report-key-stat,#rep .hue-forest .metric-stat{color:#2f8f4e}
#rep .hue-violet .report-key-icon,#rep .hue-violet .metric-icon{background:#efeafc;color:#6b4fd0}
#rep .hue-violet .report-key-stat,#rep .hue-violet .metric-stat{color:#6b4fd0}

/* ── DRINKING WATER ─────────────────────────────────────────────────────────
   Owner-approved layout. Deliberately built on the SAME spacing tokens as the
   FEMA section below -- 34px section padding, 14px card gaps, 14px radii, the
   same grey note field -- so a reader moving between them is not asked to
   re-learn the rhythm. */

#rep .dw-head{display:grid;grid-template-columns:minmax(0,1fr) minmax(280px,360px);
  gap:24px;align-items:start}
#rep .dw-head-copy h2{font-size:clamp(26px,2.9vw,34px);line-height:1.1;
  letter-spacing:-.032em;margin:8px 0 0}
#rep .dw-lede{font-size:14.5px;line-height:1.55;color:var(--muted);margin:12px 0 0;
  max-width:64ch}
/* The utility card. Its tint follows the resolver's confidence: a LIKELY match
   is a review tone, never the green of a confirmed one. */
#rep .dw-utility{display:flex;gap:13px;align-items:flex-start;padding:16px 18px;
  border-radius:14px;background:#eef4fb;border:1px solid #dbe6f4}
#rep .dw-utility.state-na{background:var(--bg);border-color:var(--line)}
#rep .dw-utility-icon{width:38px;height:38px;border-radius:50%;flex:none;display:grid;
  place-items:center;background:#fff;color:#2a6fd0}
#rep .dw-utility-icon svg{width:19px;height:19px}
#rep .dw-utility-kicker{font-size:12.5px;color:var(--muted)}
#rep .dw-utility strong{display:block;font-size:17px;line-height:1.25;margin-top:3px;
  color:var(--ink)}
#rep .dw-utility-pill{display:inline-block;margin-top:9px;padding:5px 10px;
  border-radius:var(--radius-pill);background:#fdf0dc;color:#8a5a12;
  font-size:12px;font-weight:800}
#rep .dw-utility.state-good .dw-utility-pill{background:#e7f6ec;color:#1f7a4f}
#rep .dw-utility.state-na  .dw-utility-pill{background:#eceef1;color:var(--muted)}

/* Overall quality: the verdict on the left, its figures on the right. */
/* The figure column sizes to its content. It once held three figures and was
   given an equal share; now that past items and regulator actions carry their
   own cards, a fixed 1fr left a wide empty gutter beside a single figure. */
#rep .dw-quality{display:grid;grid-template-columns:minmax(0,1fr) auto;
  gap:22px;margin-top:18px;padding:20px 22px;border-radius:14px;
  background:#f1f8f3;border:1px solid #dcecdf}
#rep .dw-quality-verdict{display:flex;gap:14px;align-items:flex-start}
#rep .dw-quality-icon{width:44px;height:44px;border-radius:50%;flex:none;display:grid;
  place-items:center;background:#e2f2e7;color:#1f7a4f}
#rep .dw-quality-icon svg{width:22px;height:22px}
#rep .dw-quality-kicker{font-size:12.5px;color:var(--muted)}
#rep .dw-quality-verdict strong{display:block;font-size:20px;line-height:1.2;
  margin-top:3px;color:#1a6b45;letter-spacing:-.02em}
#rep .dw-quality-verdict p{margin:9px 0 0;font-size:13.5px;line-height:1.55;color:var(--body,#4a5568)}
#rep .dw-quality-figures{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));
  gap:16px;align-content:start}
#rep .dw-figure-stat{font-size:26px;font-weight:800;letter-spacing:-.03em;color:var(--ink)}
#rep .dw-figure-label{font-size:12.5px;line-height:1.4;color:var(--muted);margin-top:3px}

/* The two panels. Same 14px gap and radius as the FEMA cards. */
#rep .dw-pair{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:14px;margin-top:14px}
#rep .dw-panel{padding:18px 20px;border-radius:14px;border:1px solid var(--line)}
#rep .dw-panel-info{background:#eef4fb;border-color:#dbe6f4}
#rep .dw-panel-warn{background:#fdf6ec;border-color:#f3e3c8}
#rep .dw-panel-head{display:flex;align-items:center;gap:11px;flex-wrap:wrap}
#rep .dw-panel-icon{width:36px;height:36px;border-radius:50%;flex:none;display:grid;
  place-items:center;background:#fff;color:#2a6fd0}
#rep .dw-panel-icon.warn{color:#b5760f}
#rep .dw-panel-icon svg{width:18px;height:18px}
#rep .dw-panel-head h3{font-size:15.5px;line-height:1.25;margin:0;flex:1;min-width:150px}
#rep .dw-panel-pill{padding:5px 10px;border-radius:var(--radius-pill);background:#fff;
  border:1px solid var(--line);font-size:11.5px;font-weight:800;color:var(--muted)}
#rep .dw-panel-stat{font-size:24px;font-weight:800;letter-spacing:-.03em;margin-top:12px;
  color:var(--ink)}
#rep .dw-panel-stat i{font-style:normal;font-size:15px;font-weight:700}
#rep .dw-panel p{margin:9px 0 0;font-size:13.5px;line-height:1.55;color:var(--body,#4a5568)}
#rep .dw-panel-note{color:var(--muted) !important;font-size:12.5px !important}

/* Notes and source: the FEMA grey field, same padding and radius. */
#rep .dw-notes{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));
  gap:14px;margin-top:14px}
#rep .dw-note,#rep .dw-source{display:flex;gap:14px;align-items:flex-start;
  padding:18px 20px;background:var(--bg);border-radius:14px}
#rep .dw-source{margin-top:14px}
#rep .dw-note-icon{width:34px;height:34px;border-radius:50%;flex:none;display:grid;
  place-items:center;background:#e7edf5;color:#2a4d7a;margin-top:1px}
#rep .dw-note-icon svg{width:18px;height:18px}
#rep .dw-note strong,#rep .dw-source strong{display:block;font-size:14.5px;color:var(--ink)}
#rep .dw-note p,#rep .dw-source p{margin:6px 0 0;font-size:13.5px;line-height:1.55;
  color:var(--body,#4a5568)}

/* Key findings: four equal cards, the executive-summary rhythm. */
#rep .dw-findings-head{font-size:19px;letter-spacing:-.02em;margin:22px 0 12px}
#rep .dw-findings{display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));
  gap:14px}
#rep .dw-finding{padding:16px 18px;border:1px solid var(--line);border-radius:14px;
  background:#fff}
#rep .dw-finding-icon{width:34px;height:34px;border-radius:50%;display:grid;
  place-items:center;background:#eef2f7;color:#2a4d7a}
#rep .dw-finding-icon svg{width:17px;height:17px}
#rep .dw-finding.state-review .dw-finding-icon{background:#fdf0dc;color:#b5760f}
/* Tone on a promoted record card colours the ICON, never the card body. The
   generic #rep .state-* rules set a background and a muted body colour, which
   greyed the whole card out beside its neighbours. NEUTRAL IS NOT GOOD NEWS:
   state-na stays grey and never borrows the green success treatment. */
#rep .dw-panel.dw-tone-state-review .dw-panel-icon{background:#fdf0dc;color:#b5760f}
#rep .dw-panel.dw-tone-state-na .dw-panel-icon{background:#eef1f5;color:#69778a}
/* One consolidated scope note spans the row rather than leaving a half-width
   card beside empty space. */
#rep .dw-note-wide{grid-column:1/-1}
#rep .dw-note-wide p+p{margin-top:7px}
#rep .dw-finding h4{font-size:14.5px;line-height:1.3;margin:11px 0 0;color:var(--ink)}
#rep .dw-finding-stat{font-size:24px;font-weight:800;letter-spacing:-.03em;margin-top:7px;
  color:var(--ink)}
#rep .dw-finding p{margin:7px 0 0;font-size:12.5px;line-height:1.5;color:var(--muted)}

@media(max-width:900px){
  #rep .dw-head{grid-template-columns:1fr}
  #rep .dw-quality{grid-template-columns:1fr;gap:18px}
}
@media(max-width:640px){
  
}

/* ── FEMA FLOOD MAPPING ─────────────────────────────────────────────────────
   Owner-approved layout, tighter than the standard section rhythm: the three
   cards and the note read as one block rather than four separated bands. */





/* Three equal cards. auto-fit so they collapse to one column on a narrow
   screen without a breakpoint having to undo a fixed three-column track. */
#rep .flood-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:14px;margin-top:22px}
#rep .flood-card{background:#fff;border:1px solid var(--line);border-radius:14px;
  padding:16px 18px 18px}
#rep .flood-card-kicker{font-size:11.5px;font-weight:700;letter-spacing:.09em;
  text-transform:uppercase;color:var(--muted)}
#rep .flood-card-main{display:flex;align-items:center;gap:12px;margin-top:12px}
#rep .flood-card-icon{width:38px;height:38px;border-radius:50%;flex:none;display:grid;
  place-items:center;background:#eaf0f8;color:#2a4d7a}
#rep .flood-card-icon svg{width:19px;height:19px}
#rep .flood-card-main strong{font-size:17px;line-height:1.2;letter-spacing:-.015em;
  color:var(--ink)}
/* The copy aligns under the HEADLINE, not the icon, so the three cards read as
   a row of statements rather than three separate icon blocks. */
#rep .flood-card-copy{font-size:13.5px;line-height:1.5;color:var(--muted);
  margin:10px 0 0;padding-left:50px}

/* The note carries the interpretation. Same grey field as the mockup, and the
   icon is optically centred on the first line rather than the block. */
#rep .flood-note{display:flex;gap:14px;align-items:flex-start;margin-top:16px;
  padding:18px 20px;background:var(--bg);border-radius:14px}
#rep .flood-note-icon{width:34px;height:34px;border-radius:50%;flex:none;display:grid;
  place-items:center;background:#e7edf5;color:#2a4d7a;margin-top:1px}
#rep .flood-note-icon svg{width:18px;height:18px}
#rep .flood-note strong{display:block;font-size:15.5px;color:var(--ink)}
#rep .flood-note p{margin:7px 0 0;font-size:14px;line-height:1.6;color:var(--body,#4a5568)}
#rep .flood-source{font-size:12.5px;color:var(--muted);margin:16px 0 0}

@media(max-width:640px){
  
  /* The copy loses its indent on one column: with the cards full width the
     hanging alignment stops helping and just wastes the line. */
  #rep .flood-card-copy{padding-left:0}
}

/* ── EXECUTIVE SUMMARY: FOUR CARDS ──────────────────────────────────────────
   Owner-approved layout. One row of four equal cards, each leading with its
   own figure, and a full-width gap note beneath.

   auto-fit + minmax rather than a fixed `repeat(4,1fr)`: four 250px cards need
   ~1080px of content width, and a fixed four-column track survives into a
   narrow viewport and pushes the figures off-screen. This reflows to 2x2 and
   then to one column without a breakpoint having to remember to undo it. */
#rep .exec-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:18px;margin-top:26px}
#rep .exec-card{display:flex;flex-direction:column;background:#fff;
  border:1px solid var(--line);border-radius:18px;overflow:hidden}
#rep .exec-card-body{padding:22px 20px 18px;display:flex;flex-direction:column;flex:1}
#rep .exec-card-head{display:flex;align-items:flex-start;gap:11px}
#rep .exec-card-icon{width:38px;height:38px;border-radius:12px;flex:none;
  display:grid;place-items:center}
#rep .exec-card-icon svg{width:20px;height:20px}
#rep .exec-card-head h3{font-size:16px;line-height:1.25;letter-spacing:-.01em;
  margin:5px 0 0;color:var(--ink)}
/* min-height reserves three lines of copy, so a card whose explanation runs
   short does not lift its figure above the others. Measured at 254px card
   width: the longest explanation runs FOUR lines (84px) while the rest run
   three (63px), so a three-line reserve still left the row of numbers ragged.
   Four lines is the real ceiling for this copy at this width.

   Cards are equal height regardless -- this aligns the FIGURES inside them.
   It reserves space rather than truncating: a longer explanation still wraps
   and pushes down, which is the honest failure direction. */
#rep .exec-card-copy{font-size:13.5px;line-height:1.55;color:var(--muted);
  margin:14px 0 0;min-height:calc(13.5px * 1.55 * 4)}
/* margin-top:auto pins the figure to the BOTTOM of every card, so the numbers
   align across the row however uneven the copy above them is. */
#rep .exec-card-figure{margin-top:auto;padding-top:20px}
#rep .exec-card-stat{font-size:38px;line-height:1;font-weight:800;letter-spacing:-.035em}
#rep .exec-card-stat i{font-style:normal;font-size:19px;font-weight:800;margin-left:3px}
/* Two lines reserved for the same reason as the copy above: the figure block
   is bottom-anchored, so a caption that wraps starts HIGHER and lifts its
   number out of line with the rest. Measured at 254px: "Rainfall above
   estimated outdoor demand" wraps to two lines (35px) while the others fit one
   (18px), which put that card's 38px figure 18px above its neighbours. */
#rep .exec-card-cap{font-size:12.5px;line-height:1.4;color:var(--muted);margin-top:7px;
  min-height:calc(12.5px * 1.4 * 2)}
/* The band carries the card's photograph, over the card's own hue wash. The
   wash is the FALLBACK layer, not decoration: a card whose topic has no image
   -- or whose image fails to load -- still renders a filled band rather than a
   hole, so the composition holds either way.

   background-size:cover on a 1200x532 source at ~254px wide crops to the middle
   band of the photograph, which is where each of these images carries its
   subject. */
#rep .exec-card-band{position:relative;min-height:86px;display:flex;align-items:flex-end;
  padding:12px;background:var(--exec-band,#eef1f5);
  background-image:var(--exec-photo,none);background-size:cover;
  background-position:center 55%;background-repeat:no-repeat}
#rep .exec-card-pill{display:inline-flex;align-items:center;gap:6px;
  background:rgba(255,255,255,.94);border-radius:var(--radius-pill);
  padding:7px 12px;font-size:12.5px;font-weight:800;line-height:1;
  box-shadow:0 1px 3px rgba(16,35,63,.14)}
#rep .exec-card-pill-icon{display:grid;place-items:center;width:15px;height:15px;flex:none}
#rep .exec-card-pill-icon svg{width:15px;height:15px}
#rep .exec-card-pill.state-good{color:#1f8f5f}
#rep .exec-card-pill.state-review{color:#b06a12}
#rep .exec-card-pill.state-na{color:var(--muted)}

/* Per-hue: icon chip, figure colour, and the band wash behind the pill. */
#rep .exec-card.hue-blue   .exec-card-icon{background:#e8f1fc;color:#1f6fd0}
#rep .exec-card.hue-blue   .exec-card-stat{color:#1f6fd0}
#rep .exec-card.hue-blue   {--exec-band:#dbe9f8}
#rep .exec-card.hue-green  .exec-card-icon{background:#e7f6ec;color:#1f8f5f}
#rep .exec-card.hue-green  .exec-card-stat{color:#1f8f5f}
#rep .exec-card.hue-green  {--exec-band:#dcefe2}
#rep .exec-card.hue-amber  .exec-card-icon{background:#fdf0dc;color:#e07b1a}
#rep .exec-card.hue-amber  .exec-card-stat{color:#e07b1a}
#rep .exec-card.hue-amber  {--exec-band:#f8e6cd}
#rep .exec-card.hue-forest .exec-card-icon{background:#e6f4e9;color:#2f8f4e}
#rep .exec-card.hue-forest .exec-card-stat{color:#2f8f4e}
#rep .exec-card.hue-forest {--exec-band:#dcecdf}
#rep .exec-card.hue-violet .exec-card-icon{background:#efeafc;color:#6b4fd0}
#rep .exec-card.hue-violet .exec-card-stat{color:#6b4fd0}
#rep .exec-card.hue-violet {--exec-band:#e5ddf7}

/* ── CARD PHOTOGRAPHS, BOUND BY TOPIC ──────────────────────────────────────
   Keyed on the icon topic (drop / leaf / sun / tree), which is derived from the
   group itself in groupIcon(). Binding to the card's POSITION would silently
   mis-pair every image the day a group is added, reordered or drops out for
   want of data -- a report showing cracked earth beside a tree-cover figure.
   Binding to the display title would break the first time the copy is reworded.

   A topic with no photograph keeps its hue wash, which is why the fallback
   above is not removed now that images exist. */
#rep .exec-card.topic-drop  .exec-card-band{--exec-photo:url('waterfax_exec_dry_periods.jpg')}
#rep .exec-card.topic-leaf  .exec-card-band{--exec-photo:url('waterfax_exec_outdoor_water_use.jpg')}
#rep .exec-card.topic-sun   .exec-card-band{--exec-photo:url('waterfax_exec_summer_heat.jpg')}
#rep .exec-card.topic-tree  .exec-card-band{--exec-photo:url('waterfax_exec_tree_cover.jpg')}
/* The pill sits ON the photograph now, so it needs its own contrast rather than
   borrowing the band's. Slightly more opaque and a soft shadow, so it reads over
   a bright sprinkler shot as clearly as over a dark canopy. */
#rep .exec-card-band .exec-card-pill{background:rgba(255,255,255,.96);
  box-shadow:0 1px 4px rgba(16,35,63,.24)}

/* ── THE GAP NOTE ─────────────────────────────────────────────────────────
   Full width beneath the cards, never a fifth card: what could not be checked
   is stated as plainly as the findings, but it is not dressed as a finding. */
#rep .exec-gap{display:flex;align-items:center;gap:14px;margin-top:18px;
  padding:16px 18px;background:var(--bg);border:1px solid var(--line);
  border-radius:16px;flex-wrap:wrap}
#rep .exec-gap-icon{width:34px;height:34px;border-radius:50%;flex:none;
  display:grid;place-items:center;background:#fff;border:1px solid var(--line);
  color:var(--muted)}
#rep .exec-gap-icon svg{width:18px;height:18px}
#rep .exec-gap-body{flex:1;min-width:220px}
#rep .exec-gap-body strong{display:block;font-size:14.5px;color:var(--ink)}
#rep .exec-gap-body p{margin:4px 0 0;font-size:13px;line-height:1.5;color:var(--muted)}
#rep .exec-gap-link{flex:none;background:#fff;border:1px solid var(--line);
  border-radius:var(--radius-pill);padding:9px 15px;font-size:13px;font-weight:800;
  color:var(--ink);cursor:pointer;display:inline-flex;align-items:center;gap:7px}
#rep .exec-gap-link:hover{border-color:var(--muted)}

#rep .report-state{font-size:12px;font-weight:900;border-radius:var(--radius-pill);
  padding:7px 10px;white-space:nowrap}
#rep .state-good{background:#eaf8f0;color:#17744e}
#rep .state-review{background:#fff4dc;color:#8a6200}
#rep .state-na{background:#eef1f5;color:#69778a}
/* An unperformed check: dashed, muted, and never carrying a rating chip. */
#rep .check.gap{background:var(--bg);border-style:dashed}
#rep .check.gap .val{color:var(--muted)}

/* ══ PROTOTYPE REPORT COMPONENTS ════════════════════════════════════════════
   Ported from sample-report.html's own values, not approximated from them.
   The old report stacked a title and three paragraphs eleven times; the
   prototype uses a two-column card grid where each card leads with a headline
   figure. These are the components that make that composition possible. */

#rep .report-score-summary{margin-top:16px;padding-top:4px;border-top:1px solid var(--line)}
/* One row = icon, quiet topic, coloured outcome. Hairlines carry the
   separation so weight does not have to: the previous panel was eight bold
   lines in a 340px box, which is not a summary anyone can scan. */
#rep .score-row{display:flex;align-items:center;gap:12px;padding:11px 0;
  border-bottom:1px solid #f1f3f6}
#rep .score-row:last-child{border-bottom:0}
#rep .score-row-icon{width:34px;height:34px;border-radius:50%;flex:none;
  display:grid;place-items:center}
#rep .score-row-icon svg{width:18px;height:18px}
/* The tint carries the same meaning as the outcome colour, so the row reads
   at a glance before a word of it is read. */
#rep .score-row-icon.state-good{background:#eaf6ef;color:#17744e}
#rep .score-row-icon.state-review{background:#fdf3e3;color:#8a6200}
#rep .score-row-icon.state-na{background:#eef1f5;color:#69778a}
#rep .score-row-text{display:block;min-width:0}
/* Sentence case, normal weight: the topic is a label, not a finding. */
#rep .score-row-title{display:block;font-size:14px;font-weight:700;
  color:var(--color-text);letter-spacing:0;text-transform:none;line-height:1.25}
#rep .score-row-state{display:block;font-size:13.5px;font-weight:600;margin-top:2px;
  line-height:1.35;background:none}
#rep .score-row-state.state-good{color:#17744e}
#rep .score-row-state.state-review{color:#8a6200}
#rep .score-row-state.state-na{color:#69778a}
/* A one-line qualifier under an outcome that needs its basis stated -- the
   regional groundwater row is regional, and the row should say so without
   making the reader open the evidence card. */
#rep .score-row-sub{display:block;font-size:11.5px;color:var(--muted);margin-top:2px;
  line-height:1.35}

#rep .report-evidence-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:18px}
#rep .evidence-card{border:1px solid var(--line);border-radius:18px;padding:22px;background:#fff}
#rep .evidence-card-top{display:flex;justify-content:space-between;gap:16px;align-items:flex-start}
#rep .evidence-card h3{margin:0 0 6px;font-size:19px}
#rep .evidence-card p{margin:0;color:var(--muted);font-size:14px}
/* The headline figure. Navy, not red: red is reserved for the score, and a
   grid of red numbers would read as eleven alarms. */
#rep .evidence-stat{font-size:32px;font-weight:900;color:var(--navy);
  letter-spacing:-.04em;margin:18px 0 4px}
#rep .evidence-caption{font-size:12px;color:var(--muted)}
/* Icon + title share a row, so the eye lands on the figure below rather than
   scanning nine identical text headings. */
#rep .evidence-head{display:flex;align-items:center;gap:9px}
#rep .evidence-icon{width:30px;height:30px;border-radius:9px;background:var(--soft);
  color:var(--red);display:grid;place-items:center;flex:none}
#rep .evidence-icon svg{width:17px;height:17px}
#rep .evidence-card.gap .evidence-icon{background:#eef1f5;color:var(--muted)}
/* The buyer's next step when a check could not be completed. "N/A -- no finding
   either way" is honest and useless; this is what to actually do about it. */
#rep .evidence-action{font-size:13px;line-height:1.5;margin:10px 0 0;padding:10px 12px;
  border-radius:var(--radius-md);background:var(--bg);border:1px solid var(--line);
  color:var(--color-text)}
/* One methodology note per group rather than one per card. */
#rep .evidence-group-note{font-size:12.5px;line-height:1.55;color:var(--muted);
  margin:12px 0 0}
/* An unperformed check keeps the card shape so it is counted at a glance, but
   is visibly hollow: dashed, muted, and its stat is never navy. */
#rep .evidence-card.gap{background:var(--bg);border-style:dashed}
#rep .evidence-card.gap .evidence-stat{color:var(--muted)}
#rep .evidence-why{font-size:14px;line-height:1.6;margin:14px 0 0;color:var(--color-text)}
#rep .evidence-limit{font-size:12px;line-height:1.55;color:var(--muted);margin:12px 0 0;
  padding-left:11px;border-left:2px solid var(--soft)}

#rep .mini-row{display:flex;justify-content:space-between;gap:12px;padding:11px 0;
  border-top:1px solid var(--line);font-size:13.5px}
#rep .mini-row span:last-child{font-weight:800;text-align:right}

#rep .report-chart{height:130px;margin-top:16px;border-radius:14px;position:relative;
  overflow:hidden;background:
  linear-gradient(180deg,rgba(236,48,19,.04),rgba(236,48,19,.00)),
  repeating-linear-gradient(0deg,#fff 0,#fff 31px,#eef1f5 32px)}
#rep .report-chart svg{position:absolute;inset:0;width:100%;height:100%}
#rep .report-chart-labels{display:flex;justify-content:space-between;margin-top:8px;
  font-size:10.5px;color:var(--muted)}

/* THE MAP IS THE EVIDENCE, so it takes the larger share. An even 1fr/1fr split
   made it read as a thumbnail beside a stack of cards; at 1.35fr it is the
   section's anchor and the facts are visibly secondary. */
#rep .report-property-grid{display:grid;grid-template-columns:1.35fr 1fr;gap:26px;
  align-items:stretch}
/* Two columns of facts, so six of them are a block rather than a stack. */
#rep .report-facts{grid-template-columns:1fr 1fr}
/* The map fills its column and matches the height of the cards beside it, so
   neither side leaves a gap. object-fit keeps the imagery undistorted while the
   frame takes whatever height the facts set. */
#rep .report-property-grid > .report-map{width:100%;height:100%;min-height:22rem}
#rep .report-property-grid > .report-map img{width:100%;height:100%;object-fit:cover}
/* The parcel identifier is administrative: quotable, not a headline. */
#rep .report-apn{font-size:12px;color:var(--muted);margin:12px 0 0;letter-spacing:.01em}

/* ── WHAT SURROUNDS THIS ADDRESS ─────────────────────────────────────────── */
#rep .report-surroundings{margin-top:24px;border:1px solid var(--line);
  border-radius:var(--radius-lg);padding:22px 24px;background:#fff}
#rep .report-surroundings h3{margin:0 0 16px;font-size:19px;letter-spacing:-.015em}
#rep .surround-bars{display:grid;gap:11px}
#rep .surround-row{display:grid;grid-template-columns:11.5rem 1fr 3.4rem;gap:14px;
  align-items:center}
#rep .surround-label{font-size:13.5px;color:var(--color-text)}
#rep .surround-track{height:10px;border-radius:99px;background:#eef1f5;overflow:hidden}
/* The bar IS the share: 63.5% of the analysed area fills 63.5% of the track.
   Scaling to the largest value would make a small share look substantial. */
#rep .surround-fill{display:block;height:100%;border-radius:99px;background:var(--muted)}
#rep .sf-tree_cover{background:#2f8f5b}
#rep .sf-grassland{background:#7cb861}
#rep .sf-cropland{background:#c9a227}
#rep .sf-built_up{background:#8a94a6}
#rep .sf-bare_sparse{background:#c4b8a6}
#rep .surround-val{font-size:13.5px;font-weight:800;text-align:right;
  font-variant-numeric:tabular-nums}
#rep .report-surroundings-note{font-size:12.5px;color:var(--muted);margin:16px 0 0;
  line-height:1.55}

@media(max-width:900px){
  #rep .report-property-grid{grid-template-columns:1fr}
  /* Stacked, the map sizes to its own aspect rather than stretching to match
     a column that no longer sits beside it. height:100% against an auto-height
     row pushed the frame past the viewport. */
  #rep .report-property-grid > .report-map{height:auto;min-height:0;width:100%}
  #rep .report-property-grid > .report-map img{height:auto}
  #rep .report-facts{grid-template-columns:1fr 1fr}
  #rep .surround-row{grid-template-columns:8.5rem 1fr 3rem;gap:10px}
  #rep .surround-label{font-size:12.5px}
}
/* The real satellite image only. The prototype's illustrated map is a drawing;
   rendering it would put a fabricated parcel in a paid due-diligence report. */
#rep .report-map{height:330px;border-radius:18px;border:1px solid var(--line);
  overflow:hidden;position:relative;background:var(--bg);display:grid;place-items:center}
#rep .report-map img{width:100%;height:100%;object-fit:cover;display:block}
#rep .report-map-absent{padding:24px;text-align:center;color:var(--muted);font-size:13px;
  line-height:1.6;max-width:38ch}

#rep .report-source-list{display:grid;gap:13px}
#rep .report-source{display:grid;grid-template-columns:1fr auto;gap:16px;padding:15px 0;
  border-top:1px solid var(--line);align-items:start}
#rep .report-source:first-child{border-top:0}
#rep .report-source strong{display:block}
#rep .report-source small{color:var(--muted)}
#rep .report-source-state{font-size:12px;font-weight:800;color:var(--muted);white-space:nowrap}
#rep .report-license{margin-top:22px;background:#fff7f4;border:1px solid #ffd8cf;
  border-radius:16px;padding:18px}
#rep .report-license ul{margin:10px 0 0;padding-left:20px;font-size:13px;line-height:1.7}

@media(max-width:900px){
  /* PRE-EXISTING mobile overflow, found while checking the property-context
     change: the evidence-source rows are `1fr auto`, and an outcome such as
     "Serving system not identified" measures 295px, so the row ran 36px past a
     390px viewport. Stacked, the outcome sits under its family name.
     Placed in THIS block because the base rule is defined above it -- the same
     declaration written earlier in the file simply lost. */
  #rep .report-source{grid-template-columns:1fr;gap:4px}
  #rep .report-source-state{white-space:normal;text-align:left}
  /* Stack by hierarchy, not by shrinking: the score, then the summary, then one
     card per row so a headline figure is never squeezed beside another. */
  #rep .report-evidence-grid,#rep .report-property-grid{grid-template-columns:1fr}
  #rep .report-facts{grid-template-columns:1fr}
  #rep .evidence-stat{font-size:28px}
  #rep .report-map{height:240px}
}

@media(max-width:900px){
  #rep .report-summary-grid{grid-template-columns:1fr}
  #rep .report-key-list{grid-template-columns:1fr}
  /* One figure per row on a phone. Two columns made the chips uneven
     (measured 122px vs 139px) because the captions differ in length, and a
     headline figure squeezed into 122px is not a headline. */
  #rep .metric-row{grid-template-columns:1fr}
  #rep .metric{border-left:0;border-top:1px solid var(--line)}
  #rep .metric:first-child{border-top:0}
  #rep .exec-section{padding:24px 22px}
  #rep .report-key{grid-template-columns:34px 1fr;gap:10px}
  #rep .report-key .report-state{grid-column:2;justify-self:start;margin-top:6px}
}

/* ══ PARTNER + ACCOUNT SURFACES (Phase D) ═══════════════════════════════════
   agents.html, partner-apply.html and partner-dashboard.html are direct
   prototype references. Their components are ported here rather than
   approximated; the dashboard binds to live Commercial data, never to the
   prototype's illustrative values.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Secondary page hero: smaller than the homepage's, same editorial voice. */
.page-hero{padding:74px 0 50px;
  background:radial-gradient(circle at 88% 18%,rgba(236,48,19,.08),transparent 26%),
             linear-gradient(180deg,#fff,#fbfbfc)}
section.page-hero{padding:74px 0 50px}
.page-hero-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:56px;align-items:center}
.page-hero h1{font-size:clamp(40px,6vw,76px);line-height:1.02;letter-spacing:-.05em}
.kicker{display:inline-flex;align-items:center;gap:8px;color:var(--red);
  font-weight:900;font-size:13px;letter-spacing:.12em;text-transform:uppercase}
.kicker:before{content:"";width:28px;height:2px;background:currentColor}

.partner-benefits{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.partner-benefit{background:#fff;border:1px solid var(--line);
  border-radius:var(--radius-md);padding:24px}
.partner-benefit .icon{width:42px;height:42px;border-radius:12px;background:var(--soft);
  color:var(--red);display:grid;place-items:center;font-weight:900;margin-bottom:16px}
.partner-benefit h3{font-size:18px;margin:0 0 8px}
.partner-benefit p{margin:0;color:var(--muted);font-size:14px}

.partner-flow{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
.partner-flow>div{background:#fff;border:1px solid var(--line);
  border-radius:var(--radius-md);padding:26px 24px;min-height:190px}
.step-num{width:38px;height:38px;border-radius:50%;background:var(--red);color:#fff;
  display:grid;place-items:center;font-family:var(--font-heading);font-weight:900;
  font-size:17px;margin-bottom:18px}

/* Application form: prototype's two-column shell. */
.form-shell{display:grid;grid-template-columns:.8fr 1.2fr;gap:38px;align-items:start}

/* Dashboard. Empty states must look intentional, never like a failure. */
.dash-top{display:flex;align-items:flex-start;justify-content:space-between;
  gap:24px;margin-bottom:28px;flex-wrap:wrap}
.activity{display:grid;gap:14px}
.activity-item{padding:0 0 14px;border-bottom:1px solid var(--line)}
.activity-item:last-child{border-bottom:0}
.activity-item strong{display:block}
.activity-item small{color:var(--muted)}

/* Report cards for Your Reports. */
.report-card{background:#fff;border:1px solid var(--line);border-radius:var(--radius-md);
  padding:22px;transition:.2s ease}
.report-card:hover{transform:translateY(-2px);box-shadow:0 18px 40px rgba(23,32,51,.08)}
.report-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:18px}

@media(max-width:900px){
  .page-hero-grid,.form-shell{grid-template-columns:1fr}
  .partner-benefits{grid-template-columns:1fr}
  .partner-flow{grid-template-columns:1fr 1fr}
}
@media(max-width:620px){
  .partner-flow{grid-template-columns:1fr}
  .page-hero h1{font-size:38px}
}

/* ══ HOMEPAGE ═══════════════════════════════════════════════════════════════
   Ported from the approved prototype's own stylesheet, not approximated. The
   asymmetry, the oversized headline, the negative-margin overlap and the
   generous whitespace ARE the design -- normalising any of them into a
   conventional SaaS grid is what made the first attempt wrong.
   ═══════════════════════════════════════════════════════════════════════════ */
/* <section class="hero"> matches BOTH `section` and `.hero`, so the padding is
   stated once on the combined selector rather than left to cascade order --
   the same collision the section.wrap rule above exists to prevent. */
section.hero{padding:78px 0 58px}
.hero{background:radial-gradient(circle at 84% 18%,rgba(236,48,19,.08),transparent 26%),
             linear-gradient(180deg,#fff 0%,#fff 68%,#fbfbfc 100%)}
/* Prototype proportions verbatim: the image column is FIXED-min, so the hero is
   deliberately asymmetric rather than two equal halves. */
.hero-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(470px,620px);
  gap:18px;align-items:center;position:relative}
.hero-copy{position:relative;z-index:3;padding-right:8px}
.eyebrow{display:inline-flex;align-items:center;gap:8px;color:var(--red);
  font-weight:900;font-size:13px;letter-spacing:.12em;text-transform:uppercase}
.eyebrow:before{content:"";width:28px;height:2px;background:currentColor}
/* 48-82px. Not a normal H1 -- the scale is the point. */
.hero h1{font-size:clamp(48px,7vw,82px);line-height:.98;letter-spacing:-.055em;
  margin:18px 0 24px;max-width:740px}
.hero h1 .accent{color:var(--red)}
.lead{font-size:20px;color:#536076;max-width:670px;margin-bottom:28px}
.price-line{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 18px;font-weight:800}
.price-pill{background:var(--soft);color:var(--red2);border:1px solid #ffd4ca;
  padding:8px 12px;border-radius:var(--radius-pill)}
.search-box{background:#fff;border:1px solid var(--line);box-shadow:var(--shadow);
  border-radius:18px;padding:12px;display:flex;gap:10px;max-width:690px;position:relative}
/* The input sits inside a positioned wrapper so the autocomplete list can
   anchor to it. The wrapper therefore takes the flex, and the input must fill
   it -- otherwise the field measures short and the button absorbs the slack. */
.search-box>div{flex:1;min-width:0;display:flex}
.search-box .input,.search-box input{flex:1;border:0;outline:0;padding:0 12px;
  color:var(--ink);min-width:0;background:transparent;box-shadow:none;height:46px}
.micro{font-size:13px;color:var(--muted);margin-top:12px}

/* THE OVERLAP. The image column is pulled left UNDER the copy, which is what
   gives the hero its depth; a tidy two-column split loses the composition. */
.hero-card-wrap{position:relative;overflow:visible;margin-left:-136px;padding-left:34px}
.house-panel{position:relative;border-radius:34px;overflow:hidden;min-height:560px;
  background:linear-gradient(90deg,rgba(255,255,255,.98) 0%,rgba(255,255,255,.88) 16%,
             rgba(255,255,255,.40) 34%,rgba(255,255,255,.08) 48%,rgba(255,255,255,0) 58%),
             linear-gradient(180deg,rgba(255,255,255,.06),rgba(16,35,63,.10)),
             url('waterfax_house_hero.png') center center/cover no-repeat}
.house-panel:after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(255,255,255,0) 45%,rgba(10,22,40,.10) 100%);
  pointer-events:none}
/* The sample disclosure sits ON THE CARD, not floating over the photograph.
   The card shows a real 84/100 for a specific address, so the statement has to
   stay somewhere a sighted reader sees it -- and here it matches the card's own
   aria-label instead of contradicting it. */
.samp-tag{display:inline-block;margin-left:8px;padding:2px 7px;border-radius:var(--radius-pill);
  background:var(--bg);border:1px solid var(--line);color:var(--muted);
  font-size:9.5px;font-weight:800;letter-spacing:.06em;vertical-align:1px}

/* Sample card FLOATS OVER the house, bottom-right. Not an independent column. */
.samp{position:absolute;right:20px;bottom:26px;width:min(360px,82%);
  background:rgba(255,255,255,.94);backdrop-filter:blur(8px);border-radius:22px;
  padding:22px;border:1px solid rgba(28,37,56,.14);
  box-shadow:0 22px 60px rgba(23,32,51,.16);z-index:2}
.samp-hd{display:flex;justify-content:space-between;align-items:flex-start;gap:14px}
.samp-body{padding:0;margin-top:14px}
.samp-score{display:flex;align-items:flex-end;gap:12px;margin-top:2px}
.samp-num{font-family:var(--font-heading);font-weight:900;font-size:54px;line-height:.9;
  letter-spacing:-.05em;color:var(--red);font-variant-numeric:tabular-nums}
.samp-row{padding:8px 0;border-top:1px solid var(--line);font-size:14px}
.samp-row:first-of-type{border-top:none}
.samp-k{font-weight:800;color:var(--ink);font-size:13px}
.samp-v{font-size:13px;line-height:1.4;margin:2px 0 0;color:var(--muted)}
/* Coverage footnote: the denominator disclosure, at footnote weight so it
   informs without adding a paragraph's worth of card height. */
.samp-foot{font-size:10.5px;line-height:1.3;color:var(--muted);margin:8px 0 0}

/* Credibility strip. The RULES span the viewport; the four columns sit on the
   1180px container, exactly as .trust-strip + .container .trust-grid do in the
   prototype. Previously the items themselves were full-bleed, which is what
   made the strip read as stretched across the browser. */
.trust-strip{border-top:1px solid var(--line);border-bottom:1px solid var(--line);
  background:#fff}
.strip{display:grid;grid-template-columns:repeat(4,1fr);
  width:min(1180px,calc(100% - 40px));margin:0 auto}
@media(max-width:620px){.strip{width:min(1180px,calc(100% - 24px))}}
.strip>div{padding:22px 18px;text-align:center;font-weight:800;font-size:14px}
.strip>div+div{border-left:1px solid var(--line)}

/* Editorial section scale. The heading is 34-54px, and the intro is width-
   limited so it reads as an editorial column rather than full-bleed text. */
.section-soft{background:var(--bg)}
.section-head{max-width:760px;margin-bottom:38px}
.section-head h2{font-size:clamp(34px,4.5vw,54px);line-height:1.05;
  letter-spacing:-.045em;margin:10px 0 16px}
.section-head p{font-size:18px;color:var(--muted)}

/* Six-check grid. */
.six{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.six>article{background:#fff;border:1px solid var(--line);border-radius:18px;
  padding:24px;min-height:190px;transition:.2s ease}
.six>article:hover{transform:translateY(-3px);box-shadow:0 18px 40px rgba(23,32,51,.08)}
.six-n{width:42px;height:42px;border-radius:12px;background:var(--soft);color:var(--red);
  display:grid;place-items:center;font-family:var(--font-heading);font-weight:900;
  font-size:14px;margin-bottom:22px}
.six>article h3{font-size:18px;margin:0 0 8px}
.six>article p{margin:0;color:var(--muted);font-size:14px}

/* Three-step flow. */
.steps{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.steps>div{background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius-md);padding:26px 24px}
.step-n{width:38px;height:38px;border-radius:50%;background:var(--red);color:#fff;
  display:grid;place-items:center;font-family:var(--font-heading);font-weight:900;
  font-size:17px;line-height:1;margin-bottom:16px}

/* Closing CTA band -- the one full-bleed red surface. */
.cta-band{background:var(--red);color:#fff;padding:clamp(44px,7vw,64px) clamp(20px,5vw,40px)}
.cta-band h2{color:#fff}
.cta-band .btn{background:#fff;border-color:#fff;color:var(--red)}
.cta-band .btn:hover{background:var(--soft);border-color:var(--soft)}

.scale-note{border-left:4px solid var(--red);padding:4px 0 4px 18px}

/* ── PARTNER ────────────────────────────────────────────────────────────────*/
.ref-box{background:var(--navy);color:#fff;border-radius:var(--radius-lg);padding:24px;
  display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap}
.ref-code{font-size:30px;font-weight:900;letter-spacing:.04em}
.ref-box p{color:#c9d3df;margin:5px 0 0}
.metric-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;margin:22px 0}
.metric{background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius-md);padding:22px}
.metric span{display:block;color:var(--muted);font-size:13px;font-weight:750;margin-bottom:8px}
.metric strong{font-size:31px;letter-spacing:-.04em}
.dashboard-grid{display:grid;grid-template-columns:1.15fr .85fr;gap:20px}
.partner-note{background:var(--soft);border:1px solid #ffd4ca;
  border-radius:var(--radius-md);padding:20px;color:#7a2418}

/* ── REPORT ─────────────────────────────────────────────────────────────────
   CLASS CONTRACT. These names are emitted by render() and, for the tag-*
   chips, chosen upstream in build_report.py. Restyled, never renamed. */
.checks{display:grid;grid-template-columns:repeat(2,1fr);gap:16px}
.check{background:var(--white);border:1px solid var(--line);
  border-radius:var(--radius-md);padding:24px}
.check h3{font-size:16px;margin-bottom:8px}
.check .q{font-size:12.5px;color:var(--muted);margin:0 0 8px}
.check .val{font-size:14.5px;line-height:1.5;margin:0}
.check .note{font-size:12px;color:var(--muted);margin:8px 0 0;line-height:1.45;
  border-left:3px solid var(--red);padding-left:9px}
.check .prov{font-size:11px;color:var(--color-neutral-500);margin:9px 0 0;
  font-family:ui-monospace,monospace;word-break:break-word}
/* Reserved for a check with no data. Phase E + the Product Integrity
   correction decide how a NOT-CHECKED item is presented; the treatment is
   kept here so it is not lost. */
.check.gap{background:var(--bg);border-style:dashed}
.scorebox{display:flex;gap:26px;align-items:center;flex-wrap:wrap;
  border:1px solid var(--line);border-radius:var(--radius-lg);padding:24px;
  box-shadow:var(--shadow)}
.scorenum{font-family:var(--font-heading);font-weight:900;font-size:64px;line-height:1;
  letter-spacing:-.05em;color:var(--red);font-variant-numeric:tabular-nums}
.bar{height:12px;background:var(--color-neutral-200);border:1px solid var(--line);
  border-radius:var(--radius-pill);min-width:220px;flex:1;overflow:hidden}
.bar>div{height:100%;background:var(--red)}
.chartblock{margin-top:8px}
.months{display:grid;grid-template-columns:repeat(12,1fr);gap:4px;align-items:end;
  height:110px;margin-top:14px}
.months .m{background:var(--red);min-height:2px;border-radius:4px 4px 0 0}
.mlabels{display:grid;grid-template-columns:repeat(12,1fr);gap:4px;font-size:10px;
  text-align:center;color:var(--muted);margin-top:5px}
.profile{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px;margin-top:14px}
.prow{background:var(--white);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:12px 14px;display:flex;justify-content:space-between;gap:10px;
  align-items:center;font-size:14px}
.attribution{font-size:12px;color:var(--muted)}

/* ── GENERATION / LOADING ───────────────────────────────────────────────────*/
.skel{background:linear-gradient(90deg,var(--color-neutral-200) 25%,var(--bg) 50%,var(--color-neutral-200) 75%);
  background-size:200% 100%;animation:sk 1.2s infinite;border-radius:var(--radius-sm)}
@keyframes sk{0%{background-position:200% 0}100%{background-position:-200% 0}}
@media(prefers-reduced-motion:reduce){
  *,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important;scroll-behavior:auto!important}
  .btn:hover,.six>article:hover{transform:none}
}
.stages{display:grid;gap:10px;margin-top:22px;max-width:420px}
.stage{display:flex;gap:10px;align-items:center;font-size:14px;color:var(--color-neutral-500)}
.stage.on{color:var(--ink);font-weight:700}
.stage .dot{width:10px;height:10px;border:2px solid currentColor;border-radius:50%;flex:none}
.stage.on .dot{background:var(--red);border-color:var(--red)}

/* ── TABLES ─────────────────────────────────────────────────────────────────*/
.table-wrap{overflow-x:auto}
table{width:100%;border-collapse:collapse;font-size:14px}
th,td{text-align:left;padding:12px 10px;border-bottom:1px solid var(--line)}
th{font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}

/* ── STRIPE ─────────────────────────────────────────────────────────────────
   The Payment Element renders in its own iframe and sizes to the width it is
   given, so the container must be able to shrink. WaterFax styles the
   container only and never reaches inside the frame. */
#payElement{width:100%;min-width:0;overflow:visible}
#payElement iframe{width:100%!important;min-width:0!important}
#payCard{min-width:0;overflow-wrap:anywhere}

/* ── RESPONSIVE ─────────────────────────────────────────────────────────────
   Prototype breakpoints: 900px and 620px. 320px is the floor. */
/* Prototype breakpoints. The identity survives: the headline stays oversized,
   the image keeps its rounded panel, and the sample card stays ON the house --
   it becomes a contained overlay rather than moving out into the flow. */
@media(max-width:900px){
  .hero-grid{grid-template-columns:1fr}
  section.hero{padding-top:48px}
  .hero-copy{padding-right:0}
  .hero-card-wrap{max-width:760px;margin-left:0;padding-left:0}
}
@media(max-width:900px){
  /* The prototype's mobile header shows the brand and the CTA. Replacing that
     CTA with a Menu button was not prototype fidelity, so the text links
     collapse into the disclosure while the primary button stays visible. The
     group keeps its flex context -- display:contents dropped it out of the bar
     and wrapped the CTA onto a second row. */
  /* The header row itself must not wrap -- brand, menu and CTA belong on one
     line, as in the prototype. The disclosure panel is forced onto its own row
     with a 100% basis instead, so it still opens beneath the bar. */
  /* 12px gutter matches the prototype's mobile container. The bar is tight at
     390px -- brand + disclosure + CTA -- so the brand gives up a little size
     rather than the row giving up its single line. */
  .nav{gap:8px;padding-left:12px;padding-right:12px;flex-wrap:wrap}
  .nav-brand{font-size:21px;gap:8px}
  .nav-brand .brand-mark{width:30px;height:30px;box-shadow:inset 0 0 0 6px #fff;border-width:4px}
  .navlinks{gap:8px;margin-left:auto;flex-wrap:nowrap}
  .navlinks a{display:none}
  .navlinks .btn{display:inline-flex;white-space:nowrap;padding:0 14px}
  /* An icon-sized disclosure. Three full-width controls did not fit 390px and
     forced the bar onto two rows; the prototype's bar is one 76px row. The
     accessible name is on the button text, not the glyph. */
  .mobile-menu{display:inline-flex;padding:0 12px;min-width:44px}
  .nav-panel.open{flex-basis:100%;order:99}
  .six{grid-template-columns:repeat(2,1fr)}
  .steps,.dashboard-grid,.form-grid{grid-template-columns:1fr}
  .strip{grid-template-columns:repeat(2,1fr)}
  .strip>div:nth-child(3){border-left:0}
  .strip>div:nth-child(n+3){border-top:1px solid var(--line)}
  .metric-grid{grid-template-columns:1fr 1fr}
  .grid2{grid-template-columns:1fr}
  #rep .checks{grid-template-columns:1fr}
}
@media(max-width:620px){
  /* The gutter is already inside .wrap's width (min(1180px, 100% - 40px)).
     Adding padding here stacked a SECOND gutter, so mobile content started at
     x=36 against the prototype's x=12 and ran 48px narrow. The prototype
     narrows the gutter at this breakpoint by changing the WIDTH, not by
     adding padding. */
  .wrap{width:min(1180px,calc(100% - 24px))}
  section{padding:52px 0 36px}
  section.wrap{padding:52px 0 36px}
  /* Prototype: 49px headline, shorter panel, full-width search, and the sample
     card spans the panel instead of floating in a corner too small to hold it. */
  section.hero{padding:34px 0 44px}
  .hero h1{font-size:49px}
  .lead{font-size:17px}
  .search-box{flex-direction:column;padding:12px}
  .search-box .btn{width:100%}
  /* The positioned wrapper is a flex row on desktop; stacked it added its own
     height on top of the input's. */
  .search-box>div{width:100%;padding:0}
  .search-box .input,.search-box input{height:24px;padding:0 12px}
  .house-panel{min-height:430px;background-position:center center;
    background-image:linear-gradient(180deg,rgba(255,255,255,.10),rgba(16,35,63,.10)),
                     url('waterfax_house_hero.png')}
  .samp{right:14px;left:14px;width:auto;bottom:16px}
  .six,.strip,.metric-grid{grid-template-columns:1fr}
  .strip>div+div{border-left:0;border-top:1px solid var(--line)}
  .ref-box{flex-direction:column;align-items:flex-start}
  /* Your Reports and the partner activity table carry 5-7 columns. Rather than
     hiding data or restructuring markup, the table scrolls inside its own box
     so the PAGE never scrolls sideways. */
  section table{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;white-space:nowrap}
  .scorenum{font-size:52px}
  .samp-num{font-size:46px}
  .months{height:88px}
  /* The score bar's 220px floor plus the scorebox padding exceeds a 320px
     viewport, which would push a horizontal scrollbar onto the whole page. */
  .bar{min-width:0}
}
/* 320px floor: nothing may force a horizontal scrollbar. */
@media(max-width:360px){
  .wrap{width:min(1180px,calc(100% - 24px))}
  .btn{padding:0 14px}
  .scorebox{padding:18px}
  .card,.panel,.form-card,.partner-card{padding:18px}
}

/* ══════════════════════════════════════════════════════════════════════════
   PRINT — the report IS the PDF.

   Preserved from the pre-migration stylesheet with the class contract intact.
   downloadReport() calls window.print(), so what is printed is the report the
   customer just read; it cannot disagree with the screen. Owner decision:
   browser print stays for V1; no server-side PDF.
   ══════════════════════════════════════════════════════════════════════════ */
@media print {
  @page{margin:14mm}
  nav,.nav,.banner,#printBtn,.no-print,.mobile-menu,.nav-panel{display:none!important}
  body{background:#fff!important;color:#000!important}
  body > *:not(#s-report):not(#s-compare){display:none!important}
  /* PRINT WHAT IS ON SCREEN. Forcing both surfaces visible appended an empty
     "Compare homes" page to every report PDF -- confirmed on page 8 of the
     owner's review export. `.hidden` is how the app tracks the current screen,
     so it is honoured here: whichever surface the customer is actually looking
     at prints, and the other does not. */
  #s-report:not(.hidden),#s-compare:not(.hidden){display:block!important}
  .wrap,section.wrap{max-width:none;padding:0!important}
  /* Comparison must survive landscape without losing columns, and its property
     maps carry meaning, so their ink is preserved like the report's. */
  #s-compare table{width:100%!important;table-layout:fixed}
  #s-compare td,#s-compare th{word-wrap:break-word;overflow-wrap:anywhere;font-size:11px}
  #s-compare img, #s-compare svg{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  #s-compare tr { break-inside: avoid; page-break-inside: avoid }
  /* Strip decorative fills, but keep the ones that ARE the information. */
  .card,.panel,.check,.scorebox,.prow,.samp{background:#fff!important;box-shadow:none!important}
  /* The report sheet is a screen device: on paper the page IS the sheet. The
     cover photo, tinted ground and floating panel are dropped so the ink goes
     on the report, not on decoration. */
  #rep{background:#fff!important;padding:0!important}
  .report-paper{border:0!important;border-radius:0!important;box-shadow:none!important}
  .report-cover{background:#fff!important;min-height:0!important;padding:0 0 18px!important}
  .report-score-panel{position:static!important;width:auto!important;
    background:#fff!important;backdrop-filter:none!important;box-shadow:none!important;
    border:1px solid #000!important;margin-top:14px!important}
  .report-section{padding:18px 0!important;break-inside:auto}
  .report-footer{padding:14px 0 0!important}
  .chartblock{background:#fff!important;border:1px solid #999!important}
  /* The executive summary is the most important thing on paper, so it keeps
     its structure but loses the tints. State pills print as outlined text so
     "3 of 4 checked" survives a monochrome printer. */
  #rep .report-callout,#rep .report-callout-red{background:#fff!important;
    border:1px solid #999!important;break-inside:avoid}
  #rep .report-summary-grid{gap:14px}
  #rep .report-key{break-inside:avoid}
  #rep .report-key-icon{background:#fff!important;border:1px solid #000!important;color:#000!important}
  #rep .report-state{background:#fff!important;border:1px solid #000!important;color:#000!important}
  #rep .check.gap{background:#fff!important;border-style:dashed!important}
  .report-disclaimer{background:#fff!important;border:1px solid #999!important}
  /* Rating chips must stay legible without colour. */
  .tag{border:1px solid #000!important;color:#000!important;background:#fff!important}
  /* Keep findings and figures whole across page breaks. The month chart is one
     figure: its bars and their labels are meaningless apart. */
  .check,.card,.panel,.scorebox,figure,tr{break-inside:avoid;page-break-inside:avoid}
  .chartblock{break-inside:avoid;page-break-inside:avoid}
  h1,h2,h3{break-after:avoid;page-break-after:avoid}
  .checks{display:block!important}
  .check{margin-bottom:12px}
  /* ODbL §4.3: attribution must carry its licence URLs onto paper. A printed
     hyperlink shows no destination, so the required links would be lost. */
  .attribution { border: 1px solid #666 !important; break-inside: avoid;
                 page-break-inside: avoid; padding: 12px; margin-top: 18px }
  .attribution p { color: #000 !important }
  .attribution a[href^="http"]::after { content: " (" attr(href) ")";
                                        font-size: 10px; word-break: break-all }
  .attribution img { display: inline-block !important }
  /* These carry meaning, so their ink is preserved. */
  .bar,.bar>div,.months,.months .m,figure img{
    -webkit-print-color-adjust:exact;print-color-adjust:exact}
  /* ── REBUILT REPORT COMPONENTS ─────────────────────────────────────────
     ONE architecture in both media. The screen grid becomes a single column so
     a headline figure is never cramped, but the composition, order and content
     are the same report the customer just read. */
  #rep .report-evidence-grid,#rep .report-property-grid{grid-template-columns:1fr!important;
    gap:12px!important}
  #rep .evidence-card{break-inside:avoid;page-break-inside:avoid;
    border:1px solid #999!important;background:#fff!important;padding:16px!important}
  #rep .evidence-card.gap{border-style:dashed!important}
  /* The headline figure is the point of the card: it stays black and large. */
  #rep .evidence-stat{color:#000!important;font-size:26px!important;margin:12px 0 3px!important}
  #rep .evidence-card.gap .evidence-stat{color:#000!important}
  /* The chart's tint is decoration, but its LINE is the data. */
  #rep .report-chart{background:#fff!important;border:1px solid #999!important;
    break-inside:avoid;page-break-inside:avoid}
  #rep .report-chart svg{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  #rep .mini-row{break-inside:avoid}
  #rep .report-source,#rep .report-license{break-inside:avoid;page-break-inside:avoid}
  #rep .report-license{background:#fff!important;border:1px solid #999!important}
  #rep .report-score-summary{break-inside:avoid}
  #rep .report-map{height:auto!important;border:1px solid #999!important;
    break-inside:avoid;page-break-inside:avoid}
  #rep .report-map img{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  /* A heading stranded at the foot of a page was the loosest thing in the
     review PDF: four group headings printed with their cards on the next page.
     Keep each heading with what it introduces. */
  #rep .report-section-head,#rep .evidence-group-head{break-after:avoid;page-break-after:avoid;
    break-inside:avoid}
  /* Short closing panels must not spill two lines onto a page of their own. */
  #rep .report-disclaimer,#rep .report-summary-grid,#rep .report-footer{
    break-inside:avoid;page-break-inside:avoid}
  /* The cover and the summary that follows it are the front of the report;
     letting the section start on the cover page removes a mostly-blank page. */
  #rep .report-cover{break-after:auto;padding-bottom:8px!important}
  #rep .evidence-group-head{margin-top:20px}
  /* Generic link URLs are noise; the attribution rule above outranks this. */
  a[href]:after{content:""}
}

/* ── EVIDENCE DETAIL / WATER STORY ──────────────────────────────────────────
   The explanation layer. Built on the FEMA + drinking-water tokens (34px 48px
   section padding, 14px gaps and radii) so a reader moving between the three
   is not asked to re-learn the rhythm.

   Three cards across, then two -- the second row's cards are wider because the
   rainfall card carries a chart and the setting card carries an image. */




#rep .story-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px}
#rep .story-grid{align-items:start}
#rep .story-card{padding:20px 22px;border-radius:14px;border:1px solid var(--line);
  background:#fff;display:flex;flex-direction:column}
#rep .story-card-head{display:flex;align-items:center;gap:11px;flex-wrap:wrap;margin-bottom:14px}
#rep .story-card-icon{width:40px;height:40px;border-radius:50%;flex:none;display:grid;
  place-items:center;background:#eef4fb;color:#2f6fb5}
#rep .story-card-icon svg{width:20px;height:20px}
#rep .story-card-head h3{font-size:15.5px;line-height:1.25;margin:0;flex:1;min-width:120px}
#rep .story-card.hue-amber  .story-card-icon{background:#fdf1e3;color:#c2762a}
#rep .story-card.hue-forest .story-card-icon{background:#e9f5ec;color:#2f7d4f}
#rep .story-card.hue-violet .story-card-icon{background:#efecfb;color:#5b4bbd}

/* THE CONCLUSION IS THE HEADLINE. The measurement is demoted beneath it. */

#rep .story-detail{margin:0;font-size:13.5px;line-height:1.55;color:var(--body,#4a5568)}

/* Tiles sit under the copy, NOT pinned to the card floor. `margin-top:auto`
   pushed them to the bottom of whatever the tallest card in the row happened
   to be, opening a large empty band in every shorter card. */
#rep .story-evidence{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px}
#rep .story-stat{padding:12px 14px;border-radius:12px;background:#eef4fb;flex:1;min-width:120px}
#rep .story-stat-value{font-size:24px;font-weight:800;letter-spacing:-.03em;line-height:1.1}
#rep .story-stat-cap{margin-top:3px;font-size:12px;line-height:1.35;color:var(--muted)}
#rep .story-tile{padding:12px 14px;border-radius:12px;background:var(--bg);flex:1;min-width:110px}
#rep .story-tile-value{font-size:17px;font-weight:800;letter-spacing:-.02em;line-height:1.15}
#rep .story-tile-cap{margin-top:3px;font-size:12px;line-height:1.35;color:var(--muted)}

/* SECOND ROW: two cards over three columns. The setting card takes the spare
   column so the row reads as a deliberate 2-up rather than a 3-up with a hole
   in it, and its illustration gets room to sit beside the copy. */
#rep .story-card-setting{grid-column:span 2;display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,240px);gap:18px;align-items:start}
#rep .story-card-setting .story-card-head{grid-column:1/-1;margin-bottom:0}
#rep .story-card-setting .story-headline{grid-column:1;margin-top:14px}
#rep .story-card-setting .story-detail,
#rep .story-card-setting .story-evidence{grid-column:1}
#rep .story-card-setting .story-figure{grid-column:2;grid-row:2/span 3;align-self:stretch}

/* PLACEHOLDER IMAGE SLOT. Where the final asset does not exist yet, the card
   keeps its shape with a neutral panel rather than collapsing -- and the slot
   is visibly a placeholder, never a stand-in that could read as evidence. */
#rep .story-figure{border-radius:12px;overflow:hidden;min-height:150px;
  background:#eef4fb;display:grid;place-items:center}
#rep .story-figure img{width:100%;height:100%;object-fit:cover;display:block}
#rep .story-figure-ph{display:grid;place-items:center;gap:6px;padding:18px;
  color:#8798ad;text-align:center}
#rep .story-figure-ph svg{width:30px;height:30px;opacity:.55}
#rep .story-figure-ph span{font-size:11.5px;line-height:1.4}

@media(max-width:900px){
  #rep .story-card-setting{grid-column:span 2;grid-template-columns:minmax(0,1fr)}
  #rep .story-card-setting .story-figure{grid-column:1;grid-row:auto;min-height:130px}
}
@media(max-width:640px){
  #rep .story-card-setting{grid-column:span 1}
}
#rep .story-visual{margin-top:12px;display:flex;justify-content:center}
/* ~25% smaller than the standalone panel's 280px. The schematic communicates
   scale, not detail, so it reads perfectly well at this size and stops the
   groundwater card overshooting the one beside it.

   `!important` is deliberate and narrow: groundwaterVisual.mjs sets
   max-width:280px as an INLINE style, which a stylesheet rule cannot outrank.
   Editing that module would resize the printed keepsake too, where 280px is
   correct -- so the override is scoped to this card only. */
#rep .story-visual svg{max-width:205px !important;height:auto}
#rep .story-visual > *{margin:0}
#rep .story-visual figcaption,#rep .story-visual p{margin-top:6px !important;
  font-size:11px;line-height:1.45}

/* A CHECK WITH NO ANSWER. Legal §5: never styled as a clean result -- no green,
   no tick, and the reason stated rather than the finding omitted. */
#rep .story-card-gap{background:var(--bg);border-style:dashed}
#rep .story-blank{margin:0;font-size:13.5px;line-height:1.55;color:var(--muted)}







@media(max-width:900px){
  #rep .story-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  
  
}
@media(max-width:640px){
  #rep .story-grid{grid-template-columns:1fr}
  
  
  
}

/* ── LEGAL · LAYER 2 SHORT NOTICE ───────────────────────────────────────────
   Framework §7: required before any finding, and it MUST NOT be collapsed or
   hidden behind a link. So it is a plain visible block -- readable, not a
   dismissible banner, and not styled as decoration a reader learns to skip. */
#rep .report-notice{margin:0 48px 18px;padding:18px 22px;border-radius:14px;
  background:#f4f7fb;border:1px solid #dde5ef}
#rep .report-notice-head{display:flex;align-items:center;gap:10px;margin-bottom:9px}
#rep .report-notice-head strong{font-size:14.5px;letter-spacing:-.01em}
#rep .report-notice-icon{width:26px;height:26px;flex:none;display:grid;place-items:center;
  border-radius:50%;background:#fff;color:#2f6fb5}
#rep .report-notice-icon svg{width:15px;height:15px}
#rep .report-notice p{margin:0 0 8px;font-size:12.5px;line-height:1.6;color:var(--body,#4a5568)}
#rep .report-notice p:last-of-type{margin-bottom:10px}
#rep .report-notice-link{border:0;background:none;padding:0;cursor:pointer;
  font:inherit;font-size:12.5px;font-weight:700;color:#2f6fb5;text-decoration:underline}

/* ── LEGAL · LAYER 3 FULL DISCLAIMER ────────────────────────────────────────
   Expandable so thirteen clauses do not bury the findings, but present in full
   and never summarised. */
#rep .legal-full{margin-top:14px;border:1px solid var(--line);border-radius:14px;
  background:var(--bg)}
#rep .legal-full summary{cursor:pointer;padding:14px 18px;display:flex;
  align-items:center;justify-content:space-between;gap:12px;
  font-size:14px;font-weight:700;letter-spacing:-.01em}
#rep .legal-full summary::-webkit-details-marker{display:none}
#rep .legal-full-hint{font-size:12.5px;font-weight:700;color:#2f6fb5}
#rep .legal-full[open] .legal-full-hint::after{content:' ▲'}
#rep .legal-full:not([open]) .legal-full-hint::after{content:' ▼'}
#rep .legal-clauses{padding:0 18px 16px;display:grid;gap:13px}
#rep .legal-clause h4{margin:0 0 4px;font-size:13px;letter-spacing:-.01em;
  display:flex;gap:8px;align-items:baseline}
#rep .legal-clause-n{flex:none;width:19px;height:19px;border-radius:50%;
  background:#e6ecf4;color:#3d5a80;font-size:11px;font-weight:800;
  display:inline-grid;place-items:center}
#rep .legal-clause p{margin:0;font-size:12.5px;line-height:1.6;color:var(--body,#4a5568)}
/* The counsel placeholder is visibly unfinished ON PURPOSE: an unreviewed
   liability cap must never read as an agreed one. */
#rep .legal-clause-counsel{padding:11px 13px;border-radius:10px;background:#fdf6ec;
  border:1px dashed #e8cfa4}

#rep .report-footer-legal{margin:0 0 8px;font-size:11.5px;line-height:1.55;
  color:var(--muted);max-width:80ch}

@media(max-width:900px){ #rep .report-notice{margin:0 26px 16px} }
@media(max-width:640px){ #rep .report-notice{margin:0 20px 14px;padding:16px 18px} }

/* ── WHY THIS SCORE ─────────────────────────────────────────────────────────
   Built on the same 34px/48px section rhythm as FEMA, drinking water and the
   evidence detail, so the reader is not asked to re-learn the page. */
#rep .why-section{padding:34px 48px}
#rep .why-head{display:flex;gap:24px;align-items:flex-start;justify-content:space-between;
  flex-wrap:wrap;margin-bottom:20px}
#rep .why-head h2{font-size:26px;letter-spacing:-.025em;margin:6px 0 0}
#rep .why-qualifier{margin:8px 0 0;font-size:13px;line-height:1.55;color:var(--muted);max-width:62ch}
#rep .why-score{text-align:right;flex:none}
#rep .why-score-num{font-size:38px;font-weight:800;letter-spacing:-.04em;line-height:1}
#rep .why-score-num small{font-size:16px;font-weight:700;color:var(--muted)}
#rep .why-score-word{margin-top:2px;font-size:13px;font-weight:700;color:var(--muted)}
#rep .why-groups{display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));gap:14px}
#rep .why-group{padding:16px 18px;border-radius:14px;border:1px solid var(--line);background:#fff}
#rep .why-group-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px}
#rep .why-group-head h3{font-size:14.5px;margin:0;letter-spacing:-.01em}
#rep .why-group-weight{font-size:11.5px;color:var(--muted);flex:none}
#rep .why-bar{height:7px;border-radius:999px;background:#eef1f5;overflow:hidden;margin:12px 0 8px}
#rep .why-bar>div{height:100%;border-radius:999px;background:#2f6fb5}
#rep .why-group-figure{display:flex;align-items:baseline;gap:6px}
#rep .why-group-figure strong{font-size:20px;letter-spacing:-.02em}
#rep .why-group-figure span{font-size:12px;color:var(--muted)}
/* COVERAGE, visually distinct from the result above it: a gap must never read
   as a poor score, and never as a good one. */
#rep .why-group-gap{margin:9px 0 0;padding-top:9px;border-top:1px dashed var(--line);
  font-size:12px;color:#8a6200}
#rep .why-group-none{margin:12px 0 0;font-size:12.5px;line-height:1.5;color:var(--muted)}
#rep .why-note{margin:14px 0 0;font-size:12px;line-height:1.55;color:var(--muted)}

/* ── AT A GLANCE ────────────────────────────────────────────────────────────
   Navigation. Every row is a real button so it is keyboard reachable. */
#rep .glance-section{padding:34px 48px}
#rep .glance-head h2{font-size:26px;letter-spacing:-.025em;margin:6px 0 18px}
#rep .glance-rows{display:grid;gap:8px}
#rep .glance-row{display:grid;grid-template-columns:minmax(140px,1fr) 2fr auto;gap:14px;
  align-items:center;width:100%;text-align:left;padding:14px 16px;border-radius:12px;
  border:1px solid var(--line);background:#fff;cursor:pointer;font:inherit}
#rep .glance-row:hover{background:var(--bg)}
#rep .glance-label{font-weight:700;font-size:14px}
#rep .glance-finding{font-size:13px;color:var(--body,#4a5568)}
#rep .glance-go{color:var(--muted)}

/* ── BEFORE YOU CLOSE ───────────────────────────────────────────────────────
   Actions earned by this report. The tick is a private convenience, so it is
   styled as a quiet control rather than a claim of completion. */
#rep .todo-section{padding:34px 48px}
#rep .todo-head{display:flex;gap:24px;align-items:flex-start;justify-content:space-between;
  flex-wrap:wrap;margin-bottom:18px}
#rep .todo-head h2{font-size:26px;letter-spacing:-.025em;margin:6px 0 0}
#rep .todo-lede{margin:8px 0 0;font-size:13.5px;line-height:1.55;color:var(--muted);max-width:64ch}
#rep .todo-progress{font-size:13px;font-weight:700;color:var(--muted);flex:none}
#rep .todo-items{list-style:none;margin:0;padding:0;display:grid;gap:10px;counter-reset:todo}
#rep .todo-item{display:grid;grid-template-columns:auto 1fr;gap:14px;align-items:start;
  padding:16px 18px;border-radius:14px;border:1px solid var(--line);background:#fff}
#rep .todo-item.is-done{background:var(--bg)}
#rep .todo-item.is-done .todo-body h3{text-decoration:line-through;color:var(--muted)}
#rep .todo-tick{flex:none;padding:0;border:0;background:none;cursor:pointer}
#rep .todo-tick-box{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;
  border:1.5px solid var(--line);color:transparent;background:#fff}
#rep .todo-tick-box svg{width:15px;height:15px}
#rep .todo-tick[aria-pressed="true"] .todo-tick-box{background:#e7f6ec;border-color:#bfe4cd;
  color:#1f7a4f}
#rep .todo-body h3{font-size:15px;margin:2px 0 0;letter-spacing:-.01em}
#rep .todo-body p{margin:6px 0 0;font-size:13.5px;line-height:1.55;color:var(--body,#4a5568)}
#rep .todo-meta{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
#rep .todo-meta span{padding:4px 9px;border-radius:var(--radius-pill);background:var(--bg);
  font-size:11.5px;color:var(--muted)}
#rep .todo-note{margin:12px 0 0;font-size:11.5px;line-height:1.5;color:var(--muted)}

@media(max-width:900px){
  #rep .why-section,#rep .glance-section,#rep .todo-section{padding:30px 26px}
  #rep .glance-row{grid-template-columns:1fr auto;gap:6px}
  #rep .glance-finding{grid-column:1/-1}
}
@media(max-width:640px){
  #rep .why-section,#rep .glance-section,#rep .todo-section{padding:26px 20px}
  #rep .why-head h2,#rep .glance-head h2,#rep .todo-head h2{font-size:22px}
  #rep .why-score{text-align:left}
}

/* ── ESTIMATED SUPPLEMENTAL IRRIGATION ──────────────────────────────────────
   A scenario tool. Styled as a calm estimate rather than a dashboard readout,
   because the area is the reader's assumption, not a WaterFax measurement. */
#rep .lawn-section{padding:34px 48px}
#rep .lawn-head h2{font-size:26px;letter-spacing:-.025em;margin:6px 0 0}
#rep .lawn-lede{margin:8px 0 0;font-size:14px;line-height:1.6;color:var(--body,#4a5568);max-width:66ch}
#rep .lawn-tool{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:24px;
  align-items:center;margin-top:18px;padding:20px 22px;border-radius:14px;
  border:1px solid var(--line);background:#fff}
#rep .lawn-control label{display:block;font-size:12.5px;font-weight:700;color:var(--muted);
  margin-bottom:10px}
#rep .lawn-control input[type=range]{width:100%;accent-color:#2f6fb5}
#rep .lawn-control output{display:block;margin-top:8px;font-size:14px;font-weight:700}
#rep .lawn-result{text-align:right;flex:none}
#rep .lawn-gallons{font-size:34px;font-weight:800;letter-spacing:-.035em;line-height:1}
#rep .lawn-gallons-cap{margin-top:3px;font-size:12px;color:var(--muted)}
#rep .lawn-assumption{margin:12px 0 0;font-size:12px;line-height:1.55;color:var(--muted);max-width:78ch}

/* ── SHARE ──────────────────────────────────────────────────────────────────
   No reward, no code, no earnings: none exists, so none is shown. */
#rep .share-section{padding:34px 48px}
#rep .share-head h2{font-size:24px;letter-spacing:-.025em;margin:6px 0 0}
#rep .share-lede{margin:8px 0 0;font-size:13.5px;line-height:1.6;color:var(--body,#4a5568);max-width:66ch}
#rep .share-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}
#rep .share-btn{padding:10px 18px;border-radius:9px;border:1px solid var(--line);
  background:#fff;font:inherit;font-size:13.5px;font-weight:700;cursor:pointer;
  text-decoration:none;color:inherit;display:inline-block}
#rep .share-btn:hover{background:var(--bg)}
#rep .share-btn-primary{background:#17223a;border-color:#17223a;color:#fff}
#rep .share-btn-primary:hover{background:#24324f}

/* ── KEEP WATCHING ──────────────────────────────────────────────────────────
   An announcement, not an offer. No switch and no email field, because there
   is no notification backend and no consent flow behind them. */
#rep .watch-section{padding:0 48px 34px}
#rep .watch-body{display:flex;gap:12px;align-items:flex-start;padding:16px 18px;
  border-radius:14px;background:var(--bg);border:1px dashed var(--line)}
#rep .watch-icon{width:26px;height:26px;flex:none;display:grid;place-items:center;
  border-radius:50%;background:#fff;color:var(--muted)}
#rep .watch-icon svg{width:15px;height:15px}
#rep .watch-body strong{font-size:14px;letter-spacing:-.01em}
#rep .watch-body p{margin:5px 0 0;font-size:12.5px;line-height:1.55;color:var(--body,#4a5568)}

@media(max-width:900px){
  #rep .lawn-section,#rep .share-section{padding:30px 26px}
  #rep .watch-section{padding:0 26px 30px}
  #rep .lawn-tool{grid-template-columns:1fr;gap:16px}
  #rep .lawn-result{text-align:left}
}
@media(max-width:640px){
  #rep .lawn-section,#rep .share-section{padding:26px 20px}
  #rep .watch-section{padding:0 20px 26px}
  #rep .lawn-head h2,#rep .share-head h2{font-size:21px}
}

/* PRINT: the slider is replaced by a static snapshot of the chosen scenario,
   and controls that cannot work on paper are removed rather than printed dead. */
@media print{
  #rep .lawn-control input[type=range]{display:none}
  #rep .lawn-control::after{content:attr(data-print);font-size:13px;font-weight:700}
  #rep .share-actions,#rep .glance-go,#rep .todo-tick{display:none !important}
  #rep .glance-row{cursor:default}
}

/* ══ V3 DESIGN AUTHORITY ═══════════════════════════════════════════════════
   Geometry and values ported from the design package's own stylesheet, not
   approximated. The report is the package's design populated with live data.

   ── HERO ───────────────────────────────────────────────────────────────────
   ONE composition: the photograph and the score card are two columns of a
   single bordered panel. Previously the score was an aside floating over a
   cover, which is the specific thing the design authority replaces. */
#rep .hero{position:relative;overflow:hidden;border-radius:22px;display:grid;
  grid-template-columns:minmax(0,1.6fr) minmax(330px,1fr);
  background:radial-gradient(120% 90% at 100% 0%,#FFE4DC 0%,#FFF6F3 38%,#FFFFFF 70%);
  border:1px solid var(--line);box-shadow:var(--shadow)}
#rep .hero-photo{position:relative;margin:0;container-type:inline-size;
  aspect-ratio:782/572;background:#22323b;overflow:hidden;min-width:0}
#rep .hero-photo img{position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;display:block}
#rep .hero-photo::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(15,23,41,.34) 0%,rgba(15,23,41,0) 22%,
    rgba(15,23,41,0) 80%,rgba(15,23,41,.4) 100%)}

/* THE PLATE CARRIES ITS OWN DARK BACKING. The previous gradient depended on the
   left of the photograph being quiet; a street frame does not guarantee that,
   so legibility is no longer at the mercy of what the camera saw. */
#rep .hero-plate{position:absolute;z-index:1;left:3.5%;top:23.5%;width:81%;height:45%;
  display:flex;flex-direction:column;justify-content:center;padding:0 4cqw;
  background:rgba(15,23,41,.55);backdrop-filter:blur(18px) saturate(1.1);
  -webkit-backdrop-filter:blur(18px) saturate(1.1);
  border:1px solid rgba(255,255,255,.16);border-radius:clamp(10px,1.8cqw,16px);color:#fff}
#rep .hero-eyebrow{display:inline-flex;align-items:center;gap:10px;font-weight:700;
  font-size:clamp(9px,1.45cqw,11px);letter-spacing:.16em;text-transform:uppercase;
  color:#FF7A66;margin:0}
#rep .hero-eyebrow::before{content:"";width:20px;height:2px;background:currentColor;
  border-radius:2px;flex:none}
#rep .hero-addr{font-family:var(--font-display);font-weight:800;
  font-size:clamp(1.5rem,7.4cqw,3.6rem);line-height:.98;letter-spacing:-.04em;
  margin:1.6cqw 0 0;color:#fff}
#rep .hero-addr-sub{font-family:var(--font-display);font-weight:600;
  font-size:clamp(.95rem,3.1cqw,1.5rem);letter-spacing:-.02em;
  color:rgba(255,255,255,.85);margin:1cqw 0 0}
#rep .hero-facts{display:flex;flex-wrap:wrap;gap:4px 16px;margin-top:2.4cqw;
  color:rgba(255,255,255,.75);font-size:clamp(10px,1.75cqw,13px)}
#rep .hero-facts span{display:inline-flex;gap:5px;align-items:baseline}
#rep .hero-facts b{color:#fff;font-weight:600}
/* A LICENCE OBLIGATION, not decoration: never hidden to tidy the composition. */
#rep .hero-credit{position:absolute;z-index:1;right:10px;bottom:8px;font-size:.6875rem;
  color:rgba(255,255,255,.92);background:rgba(0,0,0,.4);padding:2px 7px;border-radius:4px}
/* SAME GEOMETRY with no photograph -- an intentional panel, not a broken image. */
/* The plate occupies the middle 45% of the frame, so the fallback's own
   content sits BELOW it rather than behind it -- centred, it was hidden by the
   very panel it exists to accompany. */
#rep .hero-photo-absent{position:absolute;inset:0;display:grid;justify-items:center;
  align-content:end;gap:10px;padding:0 8% 7%;text-align:center;
  background:linear-gradient(160deg,#1b2a44,#0F1729)}
#rep .hero-photo-absent-icon{width:40px;height:40px;display:grid;place-items:center;
  border-radius:50%;background:rgba(255,255,255,.10);color:rgba(255,255,255,.75)}
#rep .hero-photo-absent-icon svg{width:21px;height:21px}
#rep .hero-photo-absent p{margin:0;font-size:13px;line-height:1.5;
  color:rgba(255,255,255,.7);max-width:34ch}

#rep .hero-side{padding:18px;display:flex;flex-direction:column;justify-content:center;
  min-width:0}
#rep .hero-side .scorecard{flex:1;justify-content:space-between}
#rep .scorecard{background:#fff;border:1px solid var(--line);border-radius:16px;
  padding:18px 20px;box-shadow:var(--shadow-card);display:flex;flex-direction:column;gap:10px}
#rep .sc-head{display:flex;justify-content:space-between;align-items:center;gap:10px}
#rep .sc-label{font-size:.6875rem;font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-2)}
#rep .sc-pill{font-size:.75rem;font-weight:700;padding:4px 10px;border-radius:999px;
  white-space:nowrap;background:var(--good-bg);color:var(--good)}
#rep .sc-pill.watch{background:var(--watch-bg);color:var(--watch)}
#rep .sc-pill.na{background:var(--info-bg);color:var(--info)}
#rep .sc-num{display:flex;align-items:baseline;gap:2px;line-height:.9}
#rep .sc-num strong{font-family:var(--font-display);font-weight:800;font-size:3.1rem;
  letter-spacing:-.045em;color:var(--red)}
#rep .sc-num span{font-family:var(--font-display);font-weight:600;font-size:1.05rem;
  color:var(--ink-2)}
#rep .sc-bar{height:8px;border-radius:6px;background:var(--bg);overflow:hidden}
#rep .sc-bar i{display:block;height:100%;background:var(--red);border-radius:6px}
#rep .sc-scale{font-size:.75rem;line-height:1.5;color:var(--muted);margin:0}
#rep .breakdown{display:grid;gap:8px;border-top:1px solid var(--line);padding-top:12px}
#rep .breakdown-h{display:flex;justify-content:space-between;font-size:.6875rem;
  font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
#rep .brow{display:grid;grid-template-columns:minmax(0,1fr) 30px;gap:4px 12px;
  align-items:center}
#rep .brow .lbl{font-size:.8125rem;font-weight:600;display:flex;justify-content:space-between;
  gap:8px;color:var(--ink)}
#rep .brow .lbl em{font-style:normal;color:var(--muted);font-weight:500;font-size:.6875rem}
#rep .brow .v{grid-row:span 2;text-align:right;font-family:var(--font-display);
  font-weight:700;font-size:.9375rem}
#rep .brow .bar{height:5px;border-radius:4px;background:var(--soft);overflow:hidden}
#rep .brow .bar i{display:block;height:100%;border-radius:4px;background:var(--red)}
#rep .brow .bar i.watch{background:#E0891A}
/* COVERAGE sits under the bar, never folded into the score above it. */
#rep .brow-gap{grid-column:1/-1;margin:1px 0 0;font-size:.6875rem;color:var(--watch)}
#rep .sc-foot{margin:2px 0 0;font-size:.6875rem;line-height:1.5;color:var(--muted)}
#rep .sc-meta{display:flex;flex-wrap:wrap;gap:4px 14px;padding-top:10px;
  border-top:1px solid var(--line);font-size:.6875rem;color:var(--muted)}

/* ── DETAIL SECTIONS: 230px RAIL + BODY ────────────────────────────────────
   The canonical geometry of the design authority, and the largest single
   difference from the previous full-width card stack. */
#rep .dsec{display:grid;grid-template-columns:230px minmax(0,1fr);gap:20px 44px;
  padding:44px 48px;border-top:1px solid var(--line)}
#rep .dsec .rail{display:flex;flex-direction:column;gap:12px;align-items:flex-start}
#rep .dsec .rail h2{font-family:var(--font-display);font-weight:800;font-size:1.6rem;
  line-height:1.05;letter-spacing:-.03em;margin:0}
#rep .dsec .rail .src{color:var(--muted);line-height:1.5;font-size:.75rem;margin:0}
#rep .dsec .body{display:flex;flex-direction:column;gap:20px;min-width:0}
#rep .dsec .lead{font-size:1.0625rem;line-height:1.6;max-width:64ch;color:var(--ink);margin:0}
#rep .dsec .lead strong{font-weight:700}
#rep .dsec .body>p{max-width:66ch;color:var(--ink-2);margin:0}

/* STATUS CHIPS carry an icon AND a label, so colour is never the only signal.
   Red is never used for a status: it is the brand colour, and an absence of
   records must never be coloured as a finding. */
#rep .chip{display:inline-flex;align-items:center;gap:6px;font-size:.75rem;font-weight:700;
  padding:4px 10px 4px 8px;border-radius:999px;white-space:nowrap;line-height:1.4}
#rep .chip svg{width:14px;height:14px;flex:none}
#rep .chip.good{background:var(--good-bg);color:var(--good)}
#rep .chip.watch{background:var(--watch-bg);color:var(--watch)}
#rep .chip.info,#rep .chip.na{background:var(--info-bg);color:var(--info)}

/* auto-FILL, not auto-fit: with five cells in a four-column row, auto-fit
   stretched the orphan across the whole remaining width and left a large empty
   band beside it. auto-fill keeps the column rhythm and wraps evenly. */
/* THREE COLUMNS at desktop: six drinking-water metrics divide evenly as 3x2,
   where auto-fill left a wide blank at the end of the final row. Narrower
   widths step down to two, then one. */
#rep .kv{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:0;
  background:#fff;border:1px solid var(--line);border-radius:12px;overflow:hidden;margin:0}
#rep .kv>div{background:#fff;padding:14px 16px;display:flex;flex-direction:column;gap:4px;
  box-shadow:1px 0 0 var(--line),0 1px 0 var(--line)}
#rep .kv dt{font-size:.75rem;color:var(--muted);font-weight:500}
#rep .kv dd{margin:0;font-family:var(--font-display);font-weight:700;font-size:1.0625rem;
  letter-spacing:-.01em}
#rep .kv dd small{display:block;font-family:var(--font-body);font-weight:400;
  font-size:.75rem;color:var(--muted);margin-top:2px;letter-spacing:0}
#rep .note{background:var(--bg);border-left:3px solid var(--red);border-radius:0 10px 10px 0;
  padding:14px 18px;display:grid;grid-template-columns:auto minmax(0,1fr);gap:12px;
  align-items:start}
#rep .note svg{width:18px;height:18px;color:var(--muted)}
#rep .note p{color:var(--ink-2);max-width:66ch;font-size:.9375rem;margin:0}
#rep .note strong{color:var(--ink)}
#rep .asks{list-style:none;margin:0;padding:0;display:grid;gap:10px}
#rep .asks li{display:grid;grid-template-columns:22px minmax(0,1fr);gap:10px;color:var(--ink-2)}
#rep .asks li::before{content:"?";font-size:.75rem;font-weight:700;width:22px;height:22px;
  border-radius:6px;display:grid;place-items:center;background:var(--soft);color:var(--red);
  margin-top:2px}
#rep .sub-h{font-family:var(--font-display);font-weight:700;font-size:1rem;
  letter-spacing:-.01em;margin:0}

/* ── FEMA HAZARD LADDER ────────────────────────────────────────────────────
   Position on the ladder is the finding. The "here" rung is GREEN because the
   evidence earned it, not because green is the default. */
#rep .ladder{display:grid;grid-template-columns:1.1fr 1.1fr 1fr 1.3fr;gap:3px}
#rep .rung{padding:12px 12px 10px;background:var(--bg);display:flex;flex-direction:column;
  gap:2px;min-width:0}
#rep .rung:first-child{border-radius:10px 0 0 10px}
#rep .rung:last-child{border-radius:0 10px 10px 0}
#rep .rung b{font-size:.8125rem;font-weight:700}
#rep .rung span{font-size:.75rem;color:var(--muted);line-height:1.35}
#rep .rung.here{background:var(--good-bg);outline:2px solid var(--good);outline-offset:-2px;
  position:relative}
#rep .rung.here b{color:var(--good)}
#rep .rung.here::after{content:"This home";position:absolute;top:-11px;right:10px;
  font-size:.6875rem;font-weight:700;background:var(--good);color:#fff;padding:1px 8px;
  border-radius:4px}
#rep .ladder-cap{display:flex;justify-content:space-between;color:var(--muted);
  margin-top:6px;gap:12px;font-size:.75rem}

/* ── DOWNPOURS ─────────────────────────────────────────────────────────────
   Climate evidence. No "preview / sample values" tag: the upstream Weather
   defect is fixed and these are the property's real figures. */
#rep .rain-card{padding:20px 22px;display:flex;flex-direction:column;gap:16px;
  border:1px solid var(--line);border-radius:14px;background:#fff}
#rep .rain-h{display:flex;justify-content:space-between;align-items:center;gap:12px;
  flex-wrap:wrap}
#rep .stat3{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}
#rep .stat{padding:12px 14px;border-radius:10px;background:var(--bg);display:flex;
  flex-direction:column;gap:2px}
#rep .stat b{font-family:var(--font-display);font-weight:800;font-size:1.75rem;
  letter-spacing:-.035em;line-height:1.05}
#rep .stat b small{font-size:.9rem;font-weight:600;color:var(--ink-2);letter-spacing:-.01em;
  margin-left:3px}
#rep .stat span{font-size:.75rem;color:var(--ink-2);line-height:1.4}

@media(max-width:900px){
  #rep .kv{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media(max-width:560px){
  #rep .kv{grid-template-columns:1fr}
}
@media(max-width:1080px){
  #rep .hero{grid-template-columns:1fr}
  #rep .hero-side{padding:0 18px 18px}
}
@media(max-width:900px){
  #rep .dsec{grid-template-columns:1fr;gap:16px;padding:34px 26px}
  #rep .dsec .rail{flex-direction:row;flex-wrap:wrap;align-items:center;gap:10px}
  #rep .dsec .rail .src{flex-basis:100%}
  #rep .ladder{grid-template-columns:repeat(2,minmax(0,1fr));gap:3px}
  #rep .rung{border-radius:10px !important}
}
@media(max-width:640px){
  #rep .dsec{padding:28px 20px}
  #rep .dsec .rail h2{font-size:1.35rem}
  #rep .sc-num strong{font-size:2.6rem}
}

/* ── THE BOTTOM LINE ────────────────────────────────────────────────────────
   Editorial verdict, not a dashboard. Ported from the design authority. */
#rep .verdict-band{margin:36px 48px 0;display:grid;
  grid-template-columns:minmax(0,1fr) auto;gap:16px 48px;align-items:end}
#rep .eyebrow{display:inline-flex;align-items:center;gap:10px;font-weight:700;
  font-size:.6875rem;letter-spacing:.16em;text-transform:uppercase;color:var(--red);margin:0}
#rep .eyebrow::before{content:"";width:20px;height:2px;background:currentColor;
  border-radius:2px;flex:none}
#rep .verdict-band h2{font-family:var(--font-display);font-weight:800;
  font-size:clamp(1.7rem,3.4vw,2.5rem);line-height:1.04;letter-spacing:-.035em;
  max-width:24ch;margin:12px 0 0}
#rep .verdict-band h2 em{font-style:normal;color:var(--red)}
#rep .verdict-band p{margin:14px 0 0;color:var(--ink-2);max-width:62ch}
/* The gap reads as a records limitation, never as a finding about the home. */
#rep .verdict-gap{font-size:.9375rem;color:var(--ink-2)}
#rep .verdict-gap strong{color:var(--ink)}
#rep .verdict-scope{font-size:.8125rem;color:var(--muted)}
#rep .verdict-meta{display:flex;flex-direction:column;gap:8px;align-items:flex-start}
#rep .vchip{font-size:.75rem;font-weight:600;padding:7px 12px;border-radius:999px;
  border:1px solid var(--line);background:#fff;color:var(--ink-2);white-space:nowrap}

/* ── BLOCKS: at-a-glance and the checklist ────────────────────────────────── */
#rep .block{margin:56px 48px 0}
#rep .block-h{display:flex;align-items:end;justify-content:space-between;gap:16px;
  flex-wrap:wrap;margin-bottom:18px}
#rep .block-h h2{font-family:var(--font-display);font-weight:800;
  font-size:clamp(1.7rem,3.2vw,2.3rem);letter-spacing:-.035em;line-height:1.05;margin:12px 0 0}
#rep .block-h p{color:var(--muted);max-width:52ch;margin:8px 0 0}
#rep .block-note{margin:12px 0 0;font-size:.75rem;color:var(--muted)}
#rep .card{background:#fff;border:1px solid var(--line);border-radius:14px}

#rep .glance{display:grid}
#rep .grow{display:grid;grid-template-columns:160px 130px minmax(0,1fr) auto;gap:8px 18px;
  align-items:center;padding:15px 22px;border-top:1px solid var(--line);color:inherit;
  text-decoration:none}
#rep .grow:first-child{border-top:0;border-radius:14px 14px 0 0}
#rep .grow:last-child{border-radius:0 0 14px 14px}
#rep .grow:hover{background:var(--bg)}
#rep .grow .t{font-family:var(--font-display);font-weight:700;letter-spacing:-.01em}
#rep .grow .f{color:var(--ink-2);font-size:.9375rem}
#rep .grow .go{color:var(--red);font-size:.75rem;font-weight:700}

#rep .checklist{list-style:none;margin:0;padding:0}
#rep .check{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:6px 16px;
  padding:20px 22px;border-top:1px solid var(--line);align-items:start}
#rep .check:first-child{border-top:0}
#rep .tick{appearance:none;width:26px;height:26px;border-radius:8px;
  border:1.5px solid var(--rule-2);background:#fff;cursor:pointer;display:grid;
  place-items:center;margin-top:2px;padding:0;color:#fff}
#rep .tick:hover{border-color:var(--red)}
#rep .tick svg{width:15px;height:15px;opacity:0;transition:opacity .15s}
#rep .tick[aria-pressed="true"]{background:var(--good);border-color:var(--good)}
#rep .tick[aria-pressed="true"] svg{opacity:1}
#rep .num-badge{display:inline-grid;place-items:center;min-width:26px;height:22px;
  padding:0 6px;border-radius:6px;background:var(--soft);color:var(--red);
  font-size:.6875rem;font-weight:700;margin-right:10px;vertical-align:2px}
#rep .check h3{font-family:var(--font-display);font-size:1.0625rem;font-weight:700;
  letter-spacing:-.015em;margin:0}
#rep .check.is-done h3{color:var(--muted);text-decoration:line-through;
  text-decoration-thickness:1px}
#rep .check p{color:var(--ink-2);margin:6px 0 0;max-width:66ch;font-size:.9375rem}
#rep .check .meta{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px;grid-column:2}
#rep .pill{font-size:.75rem;font-weight:500;padding:4px 10px;border-radius:6px;
  background:var(--bg);color:var(--ink-2)}
#rep .progress{display:flex;align-items:center;gap:12px;color:var(--muted);font-size:.8125rem}
#rep .progress .track{width:120px;height:6px;border-radius:4px;background:var(--bg);
  overflow:hidden}
#rep .progress .track i{display:block;height:100%;width:0;background:var(--good);
  border-radius:4px;transition:width .25s}

@media(max-width:900px){
  #rep .verdict-band{margin:30px 26px 0;grid-template-columns:1fr}
  #rep .block{margin:40px 26px 0}
  #rep .grow{grid-template-columns:minmax(0,1fr) auto;gap:6px 12px}
  #rep .grow .f{grid-column:1/-1}
  #rep .check{grid-template-columns:auto minmax(0,1fr)}
  #rep .check .meta{grid-column:2}
}
@media(max-width:640px){
  #rep .verdict-band{margin:26px 20px 0}
  #rep .block{margin:34px 20px 0}
}

/* ── SHARE · REFER · KEEP WATCHING ──────────────────────────────────────────
   Two columns: the share action, and the two side cards. Ported from the
   design authority. */
#rep .share{margin:64px 48px 0;display:grid;
  grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);gap:16px}
#rep .share-main{padding:clamp(20px,3vw,32px);display:flex;flex-direction:column;gap:18px;
  background:radial-gradient(120% 100% at 0% 0%,#FFF1ED 0%,#FFFFFF 55%)}
#rep .share-main h2{font-family:var(--font-display);font-weight:800;
  font-size:clamp(1.6rem,3vw,2.2rem);letter-spacing:-.035em;line-height:1.05;margin:6px 0 0}
#rep .share-main>p{color:var(--ink-2);max-width:56ch;margin:0}
#rep .share-row{display:flex;gap:8px;flex-wrap:wrap}
#rep .btn{appearance:none;border:1px solid transparent;border-radius:9px;padding:10px 16px;
  font:700 .8125rem/1 var(--font-body);cursor:pointer;display:inline-flex;align-items:center;
  gap:8px;text-decoration:none;white-space:nowrap}
#rep .btn-primary{background:var(--red);color:#fff;box-shadow:0 6px 16px rgba(229,52,29,.28)}
#rep .btn-primary:hover{background:var(--red2)}
#rep .btn-ghost{background:#fff;color:var(--ink);border-color:var(--rule-2)}
#rep .btn-ghost:hover{border-color:var(--ink-2)}
#rep .fine-print{font-size:.75rem;line-height:1.55;color:var(--muted);margin:0}

#rep .share-side{display:grid;gap:16px;align-content:start}
#rep .side{padding:22px;display:flex;flex-direction:column;gap:10px}
#rep .side h3{font-family:var(--font-display);font-size:1.125rem;font-weight:700;
  letter-spacing:-.015em;margin:0}
#rep .side p{color:var(--ink-2);font-size:.9375rem;margin:0}
#rep .side-row{display:flex;align-items:center;justify-content:space-between;gap:12px}
/* The code slot is DASHED and empty: visibly a placeholder awaiting a real
   code, never something a reader could mistake for one they can use. */
#rep .code{display:flex;align-items:center;justify-content:space-between;gap:10px;
  border:1.5px dashed var(--rule-2);border-radius:10px;padding:10px 14px;background:var(--bg)}
#rep .code b{font-weight:700;letter-spacing:.04em;color:var(--ink-2);font-size:.8125rem}
#rep .code span{font-size:.8125rem;color:var(--muted)}

@media(max-width:900px){
  #rep .share{margin:44px 26px 0;grid-template-columns:1fr}
}
@media(max-width:640px){
  #rep .share{margin:34px 20px 0}
}
