/* 住宅两个页面（市场 / 估值）共用的页面层样式。
 *
 * 这一整块原本是 prism-sfr.html 头部的内联 <style>，逐字节搬到这里（不缩进、不重排、不合并）。
 * 搬的理由与多户那份 styles/mf-page.css 完全相同：拆页之后两个页面需要同一套页面层规则，
 * 复制两份必然漂移，而漂移的样式表比没有样式表更难查 —— 两页会各自「差一点」，
 * 且没有任何一处能看出差在哪。
 *
 * ⚠️ 投资测算页（prism-sfr-underwriting.html）**不**用这份：它 2026-08-29 拆出去时
 * 就带了自己那套内联样式，已经自成一体。把它也并进来就不再是「逐字节搬」，
 * 而是一次没有判据的合并 —— 那是另一件事，要做也要单独做。
 *
 * ⚠️ <link> 必须排在 tokens.css / roles.css / prism-ds.css / resi-market.css **之后** ——
 * 它原本是内联块，位置就在所有样式表的最后，层叠顺序靠的就是这个。
 */
        * { margin: 0; padding: 0; box-sizing: border-box; }
        html, body { overflow-x: hidden; }
        .i18n-zh { display: none; }
        html[lang="zh"] .i18n-en { display: none; }
        html[lang="zh"] .i18n-zh { display: inline; }
        body {
            background: var(--canvas); color: var(--body);
            font-family: var(--font-body); font-weight: var(--fw-body);
            line-height: var(--lh-reset);
            min-height: 100vh;
        }
        a { color: inherit; }
        .mono { font-family: var(--font-mono); }
        /* .lang-toggle / nav / .logo / .logo-sub / nav a.nav-link / .nav-links removed here:
           this page has no static <nav> — the top shell is injected entirely by
           /js/prism-nav.js (its own div-based markup: .prism-shell/.ps-crumb/…, not
           nav/.logo/.nav-links), confirmed by grep: none of these six selectors ever matched
           an element in this file. Zero rendered difference; also clears their font-size/
           letter-spacing literals from the guard's worklist for free instead of converting
           dead declarations. Same finding, same fix, as prism.html (Task 9). */
        /* layout */
        .main { padding: 140px 48px 120px /* spacing: page-level hero clearance, not a component gap. Both 140px and 120px are past the 10-step ladder max of 64px -- forcing them down would visibly compress the page's top/bottom margins */; max-width: var(--w-wide); margin: 0 auto; }
        /* sub-label role: mono, uppercase, tracked. family/size/weight/text-transform now come
           from the r-label role class (added on the element below) -- r-label's default weight
           is 400, which is exactly what this rule already rendered at (no font-weight override
           here), so the role is a clean fit; only letter-spacing (2px vs r-label's 1px) and
           colour stay as page overrides. Same trade prism.html (Task 9) made for its own
           .section-label. */
        .section-label { letter-spacing: 2px /* tracking: eyebrow label tracking, wider than r-label's default 1px */;
                         color: var(--accent-strong); margin-bottom: 16px; }
        h1 {
            font-family: var(--font-display); font-weight: 500; font-size: var(--fs-display);
            color: var(--ink);
            line-height: 1.15 /* line-height: page display heading, weight 500 doesn't match r-display's 400 so this stays property-only */;
            margin-bottom: 16px;
        }
        .lede { color: var(--body); max-width: var(--w-read); margin-bottom: 32px; }
        /* input form */
        .search { background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow-sm);
                  padding: 24px; margin-bottom: 40px; }
        .row { display: flex; gap: 12px; flex-wrap: wrap; }
        .field { display: flex; flex-direction: column; gap: 8px; }
        .field label { font-size: var(--fs-caption); letter-spacing: var(--track-label); text-transform: uppercase;
                       color: var(--muted-strong); }
        .field input, .field select { background: var(--surface); border: 1px solid var(--sgs-border-2);
                       color: var(--ink); padding: 12px 16px; font-family: var(--font-body); font-size: var(--fs-body); }
        .field input:focus, .field select:focus { outline: none; border-color: var(--accent); }
        .field.addr { flex: 1 1 100%; }
        .field.num input { width: 130px; }
        .field.num.ptype select { width: 190px; }
        /* .btn adopts .a-btn.a-btn--accent (added on each button below) -- family/size/weight/
           background/border/color now come from the role. padding stays larger than a-btn's
           default (this is the page's primary CTA) and text-transform/tracking stay as page
           overrides -- same trade prism.html (Task 9) made for .btn-analyze. */
        .btn { margin-top: 16px; padding: 16px 32px; text-transform: uppercase;
               letter-spacing: var(--track-label); }
        /* .btn:hover's opacity:.88 dropped: a-btn--accent:hover already darkens the background
           (--accent -> --accent-strong) for hover feedback, and stacking the opacity dim on top
           of that measured white-on-blended-accent-strong at 4.29:1 -- below AA's 4.5:1, even
           though white-on-accent-strong alone (roles.css's own comment) is 5.39:1. Removing the
           redundant dim restores the role's own contrast instead of undercutting it. */
        .btn:disabled { opacity: 0.5; cursor: default; }
        /* results */
        #results { display: none; } #results.active { display: block; }
        /* results stack vertically, each block full-width: AI read → hero estimate → wide submarket → neighborhood */
        .cards { display: flex; flex-direction: column; gap: 20px; margin-bottom: 20px; }
        /* AI read — the narration that sits ABOVE the estimate as the face of the result. Accent-tinted
           rather than another neutral card so it reads as a distinct layer, not a fourth metric block. */
        #aiBrief { display: none; margin-bottom: 20px; padding: 20px 24px; border-radius: var(--sgs-radius);
                   background: var(--accent-soft); border: 1px solid var(--accent-line); }
        #aiBrief.active { display: block; }
        .ai-head { display: flex; align-items: center; gap: 8px; font-family: var(--sgs-font-mono);
                   font-size: var(--sgs-fs-label); letter-spacing: var(--sgs-track-label);
                   text-transform: uppercase; color: var(--sgs-accent); margin-bottom: 12px; }
        .ai-head .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--sgs-accent); flex: 0 0 auto; }
        .ai-text { font-size: var(--fs-body); line-height: 1.72 /* line-height: AI narrative prose, looser than r-body's 1.65 for readability at this length */; color: var(--sgs-ink); }
        .ai-foot { margin-top: 12px; font-size: var(--fs-caption); line-height: var(--lh-panel); color: var(--sgs-ink-3); }
        /* shimmer placeholder while the summary is generating */
        .ai-skeleton span { display: block; height: 11px; border-radius: var(--radius-sm); margin-bottom: 12px;
                            background: linear-gradient(90deg, color-mix(in srgb, var(--ink) 5%, transparent) 25%,
                            color-mix(in srgb, var(--ink) 11%, transparent) 37%, color-mix(in srgb, var(--ink) 5%, transparent) 63%);
                            background-size: 400% 100%; animation: aiShimmer 1.5s ease-in-out infinite; }
        .ai-skeleton span:nth-child(2) { width: 92%; } .ai-skeleton span:nth-child(3) { width: 74%; }
        @keyframes aiShimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
        @media (prefers-reduced-motion: reduce) { .ai-skeleton span { animation: none; } }
        @media (max-width: 620px) { #aiBrief { padding: 16px; } .ai-text { font-size: var(--fs-body); } }
        /* card + section heading now come from the shared design system (styles/prism-ds.css) */
        .card { background: var(--sgs-surface); border: 1px solid var(--border); border-radius: var(--sgs-radius); padding: 24px; }
        /* 🔴 `.comps h3` 是 2026-08-24 渲染普查抓出来补的：「Comparable sales」这个 h3 的父层是
           `.comps` 不是 `.card`，于是它漏在这条规则的作用域之外，从头到尾**没有任何 CSS 规则命中它** ——
           渲染出来是浏览器 UA 默认的 `h3 { font-size: 1.17em }` ＝ 18.72px Inter，而它的三个兄弟
           （Estimated value / Submarket intelligence / Neighborhood）都是 20px Playfair。
           与 Arial 按钮同一个根因：**UA 默认值不写在任何文件里，读源码的守卫看不见，只有渲染才认得出**。 */
        .card h3, .comps h3 { font-family: var(--sgs-font-display); font-weight: 400; font-size: var(--sgs-fs-h2);
                   color: var(--sgs-ink); margin-bottom: 16px; }
        .estimate-point { font-family: var(--sgs-font-mono); font-size: var(--fs-display); color: var(--sgs-ink); font-weight: 400; }
        .estimate-range { color: var(--sgs-ink-2); margin: 8px 0 16px; font-size: var(--fs-body); }
        /* hero estimate: full width, the number gets room to breathe */
        .card.hero { padding: 32px 40px; }
        .card.hero .estimate-point { font-size: var(--sgs-fs-hero); line-height: 1.04 /* line-height: hero estimate figure, tight metric baseline, no role covers this size */; }
        .card.hero .estimate-range { font-size: var(--fs-body); margin: 8px 0 16px; }
        @media (max-width: 620px) { .card.hero { padding: 24px; } .card.hero .estimate-point { font-size: var(--fs-display); } }
        /* submarket metrics: 2 columns so label + value fit on one line (3 cols wrapped mid-phrase) */
        #mktKV { display: grid; grid-template-columns: repeat(2, 1fr); column-gap: 32px; }
        @media (max-width: 620px) { #mktKV { grid-template-columns: 1fr; } }
        .badge { display: inline-block; padding: 4px 12px; font-size: var(--fs-caption); letter-spacing: var(--track-label);
                 text-transform: uppercase; border: 1px solid; }
        .badge.high { color: var(--up); border-color: var(--up); background: color-mix(in srgb, var(--up) 7%, transparent); }
        .badge.medium { color: var(--warn); border-color: var(--warn); background: color-mix(in srgb, var(--warn) 7%, transparent); }
        .badge.low { color: var(--down); border-color: var(--down); background: color-mix(in srgb, var(--down) 7%, transparent); }
        /* submarket metric rows — unified with the neighborhood card rows (one metric-label / value
           style everywhere): 13px sentence-case label, monospace value, shared ink tokens. */
        .kv { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 8px 0;
              border-bottom: 1px solid var(--border); font-size: var(--sgs-fs-sm); }
        .kv .k { color: var(--sgs-ink-2); } .kv .v { color: var(--sgs-ink); font-family: var(--sgs-font-mono); font-weight: 500; }
        .reasons { margin-top: 12px; font-size: var(--fs-small); color: var(--muted-strong); }
        /* confidence explanation: new-build note + "why lower confidence".
           Task 13(design-language-unification): was .conf-note, now .a-flag — every property kept
           (font-size:fs-small not a-flag's default fs-caption, since this is a real explanatory
           paragraph not a short label, same reasoning as .a-disclosure's own fs-small choice;
           color:body not a-flag's warn, so only the bolded lead-in reads as the caution, not the
           whole paragraph — a deliberate design already in place, not drift). ID-scoped (#confNote,
           set in the JS template below) so this doesn't leak onto the page's other .a-flag use
           (.est-disclaimer, inline-styled and therefore already immune either way). */
        #confNote { margin-top: 12px; font-size: var(--fs-small); line-height: var(--lh-reset); padding: 12px 16px;
                     border-left: 2px solid var(--warn); background: color-mix(in srgb, var(--warn) 6%, transparent);
                     color: var(--body); }
        #confNote b { color: var(--warn); font-weight: 500; }
        .conf-why { margin-top: 12px; font-size: var(--fs-small); line-height: var(--lh-reset); padding: 12px 16px;
                    border-left: 2px solid var(--down); background: color-mix(in srgb, var(--down) 6%, transparent);
                    color: var(--body); }
        .conf-why.medium { border-left-color: var(--warn); background: color-mix(in srgb, var(--warn) 5%, transparent); }
        .conf-why .lbl { color: var(--ink); font-weight: 500; }
        .conf-basis { margin-top: 12px; font-size: var(--fs-small); color: var(--muted-strong); }
        .conf-cov { margin-top: 12px; font-size: var(--fs-small); color: var(--muted-strong); }
        .class-label { font-family: var(--sgs-font-body); font-size: var(--fs-body); color: var(--sgs-accent); margin-bottom: 8px; }   /* 2026-08-29：内容从后台给的两词定性换成了它依据的两个数（见 renderMarket）。28px 衬线是为短标语选的字号，装两条事实会又长又吵 —— 处理跟着内容走，收到正文字号。*/
        /* narrative layer: character chips + plain-English sentences above the KV stats */
        .chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 12px; }
        .chip { font-family: var(--sgs-font-mono); font-size: var(--sgs-fs-label); letter-spacing: .5px /* tracking: compact chip label, tighter than r-label's 1px default at this small size */; text-transform: uppercase; padding: 4px 12px;
                border-radius: var(--sgs-radius-sm); border: 1px solid var(--accent-line); color: var(--sgs-accent); }
        .chip.warn { border-color: var(--warn); color: var(--warn); }
        .narrative { margin: 0 0 16px; }
        .narrative p { font-size: var(--fs-small); line-height: var(--lh-caption); color: var(--body); margin: 0 0 8px; }
        .narrative p:last-child { margin-bottom: 0; }
        /* comps table */
        .comps { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm); padding: 24px; margin-bottom: 20px; }
        table { width: 100%; border-collapse: collapse; font-size: var(--fs-small); }
        /* every column right-aligned; only the address column (.colL) is left-aligned */
        th, td { text-align: right; padding: 8px 8px; border-bottom: 1px solid var(--border); }
        th.colL, td.colL { text-align: left; }
        td.colL { white-space: nowrap; }               /* keep address on one line → uniform row height */
        th { color: var(--muted-strong); font-weight: 400; text-transform: uppercase; letter-spacing: var(--track-label); font-size: var(--fs-caption); }
        td { color: var(--body); } td.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
        /* time-adjusted price lives in its own column (uniform single-line rows) */
        td.adjv { color: var(--accent-strong); white-space: nowrap; }
        td .adj-cap { color: var(--warn); cursor: help; }
        .src-note { font-size: var(--fs-caption); line-height: var(--lh-panel); color: var(--muted-strong); margin-top: 12px; }
        /* map */
        #map { height: var(--h-map); border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: 20px; background: var(--canvas); }
        /* Basemap is now CartoDB light_all. The old filter darkened dark tiles to sit on a dark page;
           here it only needs to mute the tiles slightly so the accent markers stay the loudest thing
           on the map. Brightness is left alone — dimming a light basemap just makes it grey. */
        .map-tiles-muted .leaflet-tile-pane { filter: saturate(0.72) contrast(0.98); }
        /* loading / error */
        #loading, #errorMsg { display: none; margin: 24px 0; color: var(--body); }
        #loading.active, #errorMsg.active { display: block; }
        #errorMsg { color: var(--danger); }
        /* disclosure */
        .a-disclosure { margin-top: 40px; }   /* look comes from the shared role in styles/roles.css (Task 13: moved off tokens.css's retired .disclosure) */
        /* standard footer chrome — identical rule on the multifamily pages */
        footer { border-top: 1px solid var(--border); padding: 20px 24px; text-align: center;
                 font-size: var(--fs-small); color: var(--muted-strong); }
        /* numbered comp marker on the map — matches the comp table's # column. font: shorthand
           expanded (was writing a hardcoded family AND weight 600, two violations in one) --
           size follows .r-label's font-size (--fs-caption); weight capped to 500 per the
           heading-cap rule, same cap as everywhere else on this page. Not given the r-label
           class itself: this is a single digit in a circular pin, not tracked/uppercase text. */
        .comp-pin span { display: flex; align-items: center; justify-content: center; width: 22px; height: 22px;
                         border-radius: 50%; background: var(--accent); color: var(--on-accent);
                         font-family: var(--font-mono); font-size: var(--fs-caption); font-weight: 500;
                         border: 1px solid var(--surface); box-shadow: var(--shadow); }
        td.rownum { color: var(--accent-strong); font-family: var(--font-mono); text-align: right; }
        /* interactive Street View panorama panel (Google Maps JS StreetViewPanorama) */
        .sv-label { font-size: var(--fs-small); color: var(--body); margin-bottom: 8px; min-height: 16px; }
        #streetview { height: 380px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--canvas); overflow: hidden; }
        #streetview .sv-empty { display: flex; align-items: center; justify-content: center; height: 100%;
                                color: var(--muted-strong); font-size: var(--fs-small); text-align: center; padding: 0 16px; }
