/* ============================================================================
   Silver Fern — variant B
   Standalone stylesheet. Variant A keeps main.css untouched, so the two can be
   compared without either drifting into the other.
   ========================================================================== */

@font-face{font-family:"Inter var";font-style:normal;font-weight:300 700;font-display:swap;
  src:url("../fonts/inter-var.woff2") format("woff2")}
@font-face{font-family:"Barlow";font-style:normal;font-weight:400;font-display:swap;
  src:url("../fonts/barlow-400.woff2") format("woff2")}
@font-face{font-family:"Barlow";font-style:normal;font-weight:500;font-display:swap;
  src:url("../fonts/barlow-500.woff2") format("woff2")}
@font-face{font-family:"Great Vibes";font-style:normal;font-weight:400;font-display:swap;
  src:url("../fonts/great-vibes.woff2") format("woff2")}

:root{
  --bone:#FAF7F2;      /* warm paper, the light sections */
  --bone-hi:#FFFFFF;   /* .btn-solid:hover — a step brighter than --bone */
  --ink:#111110;       /* near-black, the dark sections */
  --ink-soft:#1A1A18;
  --fern:#2F6B4F;
  --fern-light:#8FBCA4;
  --fern-glow:#A8D4BC;
  --muted:#6B6B63;
  --muted-dark:#8A8A80;
  --hair:rgba(17,17,16,.12);
  --hair-dark:var(--line);
  --pad:clamp(20px,5vw,64px);
  --easing:cubic-bezier(.22,1,.36,1);
  /* Theme-dependent derivatives. Dark is the design's native state and these
     defaults reproduce it exactly; [data-theme="light"] remaps the lot. */
  --text-strong:rgba(250,247,242,.92);
  --text-soft:rgba(250,247,242,.78);
  --text-softer:rgba(250,247,242,.62);
  --text-faint:rgba(250,247,242,.38);  /* .foot-mark reads it; .34 was 2.96:1 */
  --edge-strong:rgba(255,255,255,.5);
  --edge:rgba(255,255,255,.26);
  --line:rgba(255,255,255,.13);
  --line-faint:rgba(255,255,255,.06);
  --warm:#E4B363;   /* rising costs — a bill, not a return */
  --star:#E4B363;   /* a filled rating star; its outline when empty */
  --fall:#D98A72;
  --surface-raise:rgba(26,26,24,.72);
}

/* Light mode: an opt-in stored per browser (menu toggle). The core swap is
   ink<->bone; everything downstream reads tokens, so the cascade follows.
   Accent greens darken — the pastels that glow on near-black wash out on
   paper. Photograph scrims (rgba(17,17,16,…)) are deliberately untouched:
   text sits on the image, not the page, in both themes. */
:root[data-theme="light"]{
  --star:#A8740E;   /* gold that still reads on paper (3.9:1) */
  --bone:#1D1D1A;
  --bone-hi:#2E2E29;
  --ink:#F4F1EA;
  --ink-soft:#FBF9F4;
  /* --muted sits on the body, which light mode inverts to dark; --muted-dark
     sits on .on-dark sections, which light mode inverts to light. Both were
     mid greys, so the first failed on its own background at 3.7:1. */
  --muted:#8E8D82;
  --muted-dark:#5E5D55;
  --hair:rgba(17,17,16,.28);
  --hair-dark:rgba(17,17,16,.14);
  --fern-glow:#2F6B4F;
  --fern-light:#2F6B4F;
  --text-strong:rgba(20,20,18,.94);
  --text-soft:rgba(20,20,18,.8);
  --text-softer:rgba(20,20,18,.64);
  --text-faint:rgba(20,20,18,.5);   /* .foot-mark reads it; .38 was 2.4:1 */
  --edge-strong:rgba(17,17,16,.5);
  --edge:rgba(17,17,16,.3);
  --line:rgba(17,17,16,.15);
  --line-faint:rgba(17,17,16,.07);
  --warm:#965F19;
  --fall:#A54D35;
  --surface-raise:rgba(255,255,255,.8);
}

/* Chart series colours arrive as inline attributes from the server, where
   themes don't exist — remapped here by value. Ugly and honest: five colours,
   five rules, no client-side chart code. */
:root[data-theme="light"] polyline[stroke="#A8D4BC"]{stroke:#2F6B4F}
:root[data-theme="light"] polyline[stroke="#8FBCA4"]{stroke:#3A6B52}
:root[data-theme="light"] polyline[stroke="#E4B363"]{stroke:#965F19}
:root[data-theme="light"] polyline[stroke="#7FA8D4"]{stroke:#2E5E96}
:root[data-theme="light"] text[fill="#A8D4BC"]{fill:#2F6B4F}
:root[data-theme="light"] text[fill="#8FBCA4"]{fill:#3A6B52}
:root[data-theme="light"] text[fill="#E4B363"]{fill:#965F19}
:root[data-theme="light"] text[fill="#7FA8D4"]{fill:#2E5E96}
:root[data-theme="light"] circle[fill="#A8D4BC"]{fill:#2F6B4F}
:root[data-theme="light"] circle[fill="#8FBCA4"]{fill:#3A6B52}
:root[data-theme="light"] circle[fill="#E4B363"]{fill:#965F19}
:root[data-theme="light"] circle[fill="#7FA8D4"]{fill:#2E5E96}
/* The benchmark grey. It was missing from this list, so the United States
   line — on nearly every chart — kept a mid-grey meant for near-black and
   washed out on cream. */
:root[data-theme="light"] polyline[stroke="#D98A72"]{stroke:#A54D35}
:root[data-theme="light"] text[fill="#D98A72"]{fill:#A54D35}
:root[data-theme="light"] circle[fill="#D98A72"]{fill:#A54D35}
:root[data-theme="light"] polyline[stroke="#8A8A80"]{stroke:#4F4E45}
:root[data-theme="light"] text[fill="#8A8A80"]{fill:#4F4E45}
:root[data-theme="light"] circle[fill="#8A8A80"]{fill:#4F4E45}

*{margin:0;padding:0;box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{
  font-family:"Barlow",ui-sans-serif,system-ui,-apple-system,sans-serif;
  background:var(--bone);color:var(--ink);line-height:1.65;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
  overflow-x:hidden}
img{display:block;max-width:100%}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
:focus-visible{outline:2px solid var(--fern-glow);outline-offset:3px;border-radius:2px}

/* ---- type scale: Inter, light weight, tight tracking (the Vex signature) ---- */
h1,h2,h3,.display{
  font-family:"Inter var",Inter,system-ui,sans-serif;font-weight:400;
  letter-spacing:-.04em;line-height:1.04}
.display{font-size:clamp(2.6rem,7.2vw,6.4rem)}
h2{font-size:clamp(2rem,4.6vw,3.9rem)}
h3{font-size:clamp(1.2rem,1.8vw,1.6rem);letter-spacing:-.025em;line-height:1.2}
.kicker{
  font-family:"Inter var",Inter,sans-serif;font-size:.68rem;font-weight:500;
  text-transform:uppercase;letter-spacing:.24em;color:var(--muted);
  margin-bottom:1.6rem;display:block}
.on-dark .kicker{color:var(--muted-dark)}
.lede{font-size:clamp(1.02rem,1.35vw,1.22rem);color:var(--muted);max-width:min(46ch,100%)}
.on-dark .lede{color:var(--muted-dark)}

.shell{padding-inline:var(--pad);max-width:1560px;margin-inline:auto}
section{padding-block:clamp(72px,11vw,168px)}
.on-dark{background:var(--ink);color:var(--bone)}

/* The nav pill is position:fixed, so an anchored jump has to clear it or the
   thing you navigated to sits underneath — 111px of it, on the promoted
   design. Lived in market.css until 8 Sep 2026, which meant it did not apply
   on the home page, whose own #homes and #how links landed behind the bar.
   A test sweeps every in-page link in b/ and insists its target has this.
   8.5rem rather than the bar's exact height: landing flush against it reads
   as clipped, and the eye wants to see that there is a top edge. */
.anchor{scroll-margin-top:calc(8.5rem + var(--banner-h,0px))}

/* -------- reading progress --------
   scaleX is compositor-only, so scrolling never triggers layout. Sits above
   the nav so it stays visible when the bar hides on scroll-down. */
.progress{position:fixed;top:0;left:0;right:0;height:2px;z-index:80;
  transform:scaleX(var(--scroll-progress,0));transform-origin:left center;
  background:linear-gradient(90deg,var(--fern),var(--fern-glow));
  pointer-events:none}

/* ========================= announcement strip =========================== */
/* Fixed above everything, and the nav is pushed down by exactly its height
   — measured into --banner-h by b.js rather than guessed, because the strip
   is one line on a laptop and two on a phone and a guess is wrong on one of
   them. Rides with the nav when that hides on scroll-down, since it is an
   announcement and not navigation. */
/* A CSS default for the height, so a blocked or failed script still leaves
   the nav below the strip rather than on top of it. b.js replaces it with
   the real measurement, which is what copes with a message long enough to
   wrap to two lines on a laptop. */
:root:has(.site-banner){--banner-h:44px}
@media (max-width:640px){:root:has(.site-banner){--banner-h:66px}}
.site-banner{position:fixed;inset-inline:0;top:0;z-index:75;
  background:var(--fern);color:var(--bone);
  transition:transform .5s var(--easing)}
.site-banner p{margin:0;padding:.62rem var(--pad);text-align:center;
  font-size:.98rem;line-height:1.45}
.site-banner span{opacity:.92}
.site-banner a{color:var(--bone);text-decoration:underline;
  text-underline-offset:3px;margin-left:.5rem;font-weight:600;
  white-space:nowrap}
.site-banner a:hover{text-decoration-thickness:2px}
/* With script, nothing shows until b.js has picked a message, so a reader
   never sees one line replaced by another. Failsafe like the reveal's: if
   the script has not acted in 2.5s the first message appears anyway, and
   a visitor without script sees it at once. */
.site-banner p[hidden]{display:none}
/* A message can carry a phone version; one of the two shows by width. */
.site-banner .banner-short{display:none}
@media (max-width:640px){
  .site-banner .banner-full{display:none}
  .site-banner .banner-short{display:inline}
}
.js .site-banner:not(.picked) p{visibility:hidden;
  animation:banner-show 0s 2.5s forwards}
@keyframes banner-show{to{visibility:visible}}
/* Stays put when the nav hides on scroll-down. It is thin, it is the
   announcement, and sliding it away would leave the returning nav floating
   over a gap where the strip used to be. */
body{padding-top:var(--banner-h,0px)}
/* On a phone it scrolls away with the page instead (Property Tax Report,
   30 Sep 2026): a message wraps to three lines there, and pinned it covered
   a fifth of every screen. With script only — b.js then gives the nav, and
   anything else pinned below the strip, what is left of it on screen
   (--banner-now), so nothing floats over a gap. Without script it stays
   pinned, as above, which never overlaps. */
@media (max-width:640px){.js .site-banner{position:absolute}}
@media (max-width:640px){
  .site-banner p{font-size:.94rem;padding:.55rem 1rem}
  .site-banner a{display:block;margin-left:0;margin-top:.15rem}
}

/* ============================ floating nav ============================== */
.nav-wrap{position:fixed;inset-inline:0;top:var(--banner-now,var(--banner-h,0px));z-index:70;padding:clamp(12px,2vw,24px) var(--pad);
  pointer-events:none;transition:transform .5s var(--easing)}
.nav-wrap.is-hidden{transform:translateY(-118%)}
.nav{
  pointer-events:auto;display:flex;align-items:center;gap:1.5rem;
  padding:.6rem .7rem .6rem 1.4rem;border-radius:999px;
  background:var(--text-soft);backdrop-filter:blur(18px) saturate(150%);
  -webkit-backdrop-filter:blur(18px) saturate(150%);
  border:1px solid var(--edge-strong);
  box-shadow:0 1px 2px rgba(17,17,16,.05),0 12px 40px rgba(17,17,16,.10);
  transition:background .4s var(--easing),border-color .4s var(--easing)}
/* Over the hero photo the bar inverts to glass-on-dark. */
.nav-wrap.on-hero .nav{background:rgba(17,17,16,.34);border-color:var(--line);color:var(--bone)}
.wordmark{font-family:"Great Vibes",cursive;font-size:clamp(1.35rem,2.1vw,1.75rem);
  line-height:1.3;white-space:nowrap;margin-right:auto;position:relative;display:inline-block}
.wordmark::after{content:"";position:absolute;left:50%;bottom:0;width:0;height:1.5px;
  transform:translateX(-50%);background:currentColor;opacity:.75;
  transition:width .45s var(--easing)}
a.brand:hover .wordmark::after,a.brand:focus-visible .wordmark::after{width:104%}
.nav-links{display:flex;gap:1.6rem;align-items:center}
/* Below this the hamburger is the navigation; the inline links would push the
   pill wider than the viewport. */
@media(max-width:900px){
  .nav-links{display:none}
  .nav{gap:.7rem;padding:.5rem .55rem .5rem 1.1rem}
  .nav-cta{padding:.55rem 1rem;font-size:.78rem}
}
.nav-links a{font-size:.86rem;letter-spacing:.01em;opacity:.78;transition:opacity .25s}
.nav-links a:hover{opacity:1}
/* The place the page is in (place-first navigation, 29 Sep 2026). */
.nav-links a[aria-current="page"]{opacity:1;font-weight:600}
/* The tax bar's links are a step larger (Ask first, 6 Oct 2026): the readers
   are older, and three words at .86rem were the smallest text in view. */
.nav-tax .nav-links a{font-size:.95rem;opacity:.85}
.nav-cta{font-family:"Inter var",Inter,sans-serif;font-size:.82rem;font-weight:500;
  padding:.62rem 1.25rem;border-radius:999px;background:var(--ink);color:var(--bone);
  white-space:nowrap;transition:background .3s,transform .3s var(--easing)}
.nav-wrap.on-hero .nav-cta{background:var(--bone);color:var(--ink)}
.nav-cta:hover{transform:translateY(-1px)}
/* Theme switch. In the header beside Apply, because that is where people
   look for it — it lived in the hamburger menu and nobody found it. Ships
   hidden; b.js reveals it, so a no-JS visitor never sees a dead control. */
.theme-btn{width:38px;height:38px;border-radius:50%;display:grid;place-items:center;
  background:none;border:1px solid var(--edge);color:inherit;cursor:pointer;
  padding:0;flex:0 0 auto;
  transition:border-color .25s var(--easing),background .25s var(--easing)}
.theme-btn:hover{border-color:var(--edge-strong);background:var(--line-faint)}
.theme-btn[hidden]{display:none}
/* Three settings since 1 Oct 2026, so the icon shows the SETTING: a sun
   for Light, a moon for Dark, a half-filled circle for Automatic (the
   device's setting); the title says what a click gives. b.js sets
   data-mode. Every rule is scoped to .theme-btn so they carry equal
   specificity — a bare `.theme-btn svg{display:block}` once outranked a
   hidden icon and drew two on top of each other. */
.theme-btn .theme-sun,.theme-btn .theme-moon,.theme-btn .theme-auto{display:none}
.theme-btn[data-mode="light"] .theme-sun{display:block}
.theme-btn[data-mode="dark"] .theme-moon{display:block}
.theme-btn[data-mode="auto"] .theme-auto{display:block}
.visually-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

.burger{width:42px;height:42px;border-radius:50%;display:grid;place-items:center;gap:3px;
  flex-shrink:0;transition:background .3s}
.burger:hover{background:rgba(17,17,16,.07)}
.nav-wrap.on-hero .burger:hover{background:var(--line)}
/* Three lines — the hamburger everyone recognises (16 Sep 2026; it
   was two, which read as "equals"). Open, the outer two slide together and
   swing into the same offset chevron the two-line icon made, and the
   middle one goes. The lines sit 3px apart (5px read as loose, judged
   16 Sep 2026); the 1.25px slide is what puts the outer two's centres
   6.5px apart when open, as the old pair's were. */
.burger span{display:block;width:17px;height:1.5px;background:currentColor;border-radius:2px;
  transition:transform .45s var(--easing),opacity .3s}
body.menu-open .burger span:nth-child(1){transform:translateY(1.25px) rotate(45deg)}
body.menu-open .burger span:nth-child(2){opacity:0;transform:scaleX(0)}
body.menu-open .burger span:nth-child(3){transform:translateY(-1.25px) rotate(-45deg)}
/* The tax bar's burger says "Menu" (Ask first, 6 Oct 2026): three lines mean
   nothing to a reader who never used an app, and the word costs 40px. The
   three lines keep their column, so the chevron rules above still apply;
   the word is a fourth span beside them. It takes the bar's right edge
   itself, since Your homes, which held it, now shows for a member only. */
.nav-tax .burger{width:auto;height:40px;border-radius:999px;padding:0 .9rem 0 .8rem;
  margin-left:auto;gap:3px .5rem;grid-template-columns:auto auto;grid-template-rows:repeat(3,auto);
  grid-auto-flow:column;align-content:center;border:1px solid rgba(127,127,127,.45)}
.member .nav-tax .burger{margin-left:0}
.nav-tax .burger span{width:16px}
.nav-tax .burger .burger-word{grid-row:1 / 4;align-self:center;width:auto;height:auto;background:none;
  font-family:"Inter var",Inter,sans-serif;font-weight:500;font-size:.92rem;letter-spacing:.01em;
  transform:none !important;opacity:1 !important}
/* Open, the word says what the next tap does: the chevron alone is the kind
   of icon this bar stopped relying on. The markup keeps "Menu" (and the
   aria-label b.js sets says the same), so the swap is the sheet's. */
body.menu-open .nav-tax .burger .burger-word{font-size:0}
body.menu-open .nav-tax .burger .burger-word::after{content:"Close";font-size:.92rem}

/* ---- full-screen menu overlay ---- */
.menu{position:fixed;inset:0;z-index:65;background:var(--ink);color:var(--bone);
  display:flex;flex-direction:column;justify-content:center;padding:clamp(80px,12vh,140px) var(--pad) var(--pad);
  clip-path:circle(0% at calc(100% - 60px) 46px);
  transition:clip-path .8s var(--easing);pointer-events:none}
body.menu-open .menu{clip-path:circle(160% at calc(100% - 60px) 46px);pointer-events:auto}
.menu-list{display:flex;flex-direction:column;gap:.1rem;margin-bottom:auto}
.menu-list a{font-family:"Inter var",Inter,sans-serif;font-weight:400;letter-spacing:-.035em;
  font-size:clamp(2.1rem,7vw,4.6rem);line-height:1.14;opacity:0;transform:translateY(28px);
  transition:opacity .5s var(--easing),transform .5s var(--easing),color .25s;
  display:flex;align-items:baseline;gap:1rem}
body.menu-open .menu-list a{opacity:1;transform:none}

/* ============================ the phone tab bar ========================= */
/* The property-tax site's primary navigation on a phone (22 Sep 2026):
   three destinations and More, in a bar at the bottom where thumbs are —
   Apple's answer to a burger, which hides the places a product lives.
   Desktop never sees it; the nav pill's links do that work there. The
   burger stays in the markup for wide screens and yields to More on a
   phone. Glass over the page's own ground, --ink: until 29 Sep 2026 it
   read --surface, which only main.css declares, so light mode got a
   near-black bar under dark labels. A hairline on top, and the safe-area inset
   so it clears the home indicator. Above the menu (z 65) so More can
   close what it opened, below the progress bar. */
:root{--tabbar-h:0px}
.tabbar{display:none}
@media(max-width:720px){
  :root:has(.tabbar){--tabbar-h:calc(3.6rem + env(safe-area-inset-bottom,0px))}
  body{padding-bottom:var(--tabbar-h)}
  .tabbar{position:fixed;inset-inline:0;bottom:0;z-index:70;display:flex;
    height:var(--tabbar-h);padding:.3rem .4rem env(safe-area-inset-bottom,0px);
    background:color-mix(in srgb,var(--ink) 82%,transparent);
    -webkit-backdrop-filter:saturate(1.4) blur(18px);backdrop-filter:saturate(1.4) blur(18px);
    border-top:1px solid var(--line)}
  .tabbar a,.tabbar-more{flex:1 1 0;display:flex;flex-direction:column;align-items:center;
    justify-content:center;gap:.22rem;min-height:44px;padding:.25rem 0;border:0;
    background:none;font:inherit;font-size:.72rem;letter-spacing:.01em;
    color:var(--text-soft);text-decoration:none;border-radius:10px;cursor:pointer}
  .tabbar svg{width:1.45rem;height:1.45rem}
  .tabbar a[aria-current]{color:var(--fern-light)}
  .tabbar a[aria-current] span{font-weight:600}
  .tabbar a:hover,.tabbar-more:hover{text-decoration:none;color:var(--text-strong)}
  .tabbar-more[aria-expanded="true"]{color:var(--fern-light)}
  .nav-wrap .burger{display:none}
  /* The menu opens from the bar now, not the corner: grow it from the
     bottom right, where More is, rather than the top right. */
  body.menu-open .menu{clip-path:circle(160% at calc(100% - 46px) calc(100% - 28px))}
  .menu{padding-bottom:calc(var(--tabbar-h) + 1rem)}
}
@media print{.tabbar{display:none !important}}
.menu-list a:hover{color:var(--fern-glow)}
.menu-list .idx{font-size:.62rem;letter-spacing:.2em;color:var(--muted-dark);
  transform:translateY(-.9em)}
.menu-foot{display:flex;flex-wrap:wrap;gap:1.4rem 2.6rem;align-items:center;
  padding-top:2.4rem;border-top:1px solid var(--hair-dark);font-size:.86rem;color:var(--muted-dark)}
.menu-foot a:hover{color:var(--bone)}
/* The Property Tax menu (16 Sep 2026): five destinations, each with a line
   saying what it is, at a size five of them fit on a phone with their
   lines. The rentals menu keeps the display-size list above. Scrolls if a
   short screen still cannot hold it — a fixed overlay that clips its own
   last entry is a menu with a page missing. */
/* The overlay starts below the banner and the pill, both of which stay
   on top of it: measured heights (b.js sets --banner-h and --nav-h), not
   a guess — the guess put the first entry under the pill. */
.menu-tax{justify-content:flex-start;overflow-y:auto;
  padding-top:calc(var(--banner-h,0px) + var(--nav-h,7rem) + 1rem)}
.menu-tax .menu-list{gap:clamp(.9rem,2.2vh,1.5rem);margin-bottom:2rem}
.menu-tax .menu-list a{font-size:clamp(1.35rem,2.4vw,1.75rem);letter-spacing:-.02em;
  line-height:1.15;align-items:flex-start}
.menu-tax .menu-list .idx{transform:translateY(.6em)}
.menu-tax .menu-item{display:flex;flex-direction:column;gap:.3rem;min-width:0}
.menu-tax .menu-desc{font-size:clamp(.95rem,1.5vw,1.1rem);letter-spacing:0;
  line-height:1.45;color:var(--muted-dark);max-width:44ch}
.menu-tax .menu-list a:hover .menu-desc{color:var(--text-soft)}
/* Three groups (Ask first, 6 Oct 2026): Do something, Look up a place,
   Browse — side by side on a wide screen, one under another on a phone,
   each entry on its own rule. The housing side is one small line under
   them, and the foot keeps the legal pages, the hub and the theme. */
.menu-groups{display:grid;gap:2rem;max-width:64rem}
@media(min-width:900px){.menu-groups{grid-template-columns:repeat(3,1fr);gap:2.6rem}}
.menu-group{padding:0;margin:0}  /* a <section>, but not a page section: no 72px foot */
.menu-group h2{font-family:"Barlow",ui-sans-serif,system-ui,sans-serif;font-size:.82rem;
  letter-spacing:.1em;text-transform:uppercase;font-weight:600;color:var(--fern-light);margin:0 0 .4rem}
.menu-tax .menu-list{gap:0;margin-bottom:0}
.menu-tax .menu-list a{border-top:1px solid var(--line);padding:.75rem 0;min-height:56px}
.menu-tax .menu-ask{margin:.4rem 0 1rem}
.menu-tax .menu-foot{padding-top:1.4rem;margin-top:1.4rem;gap:.6rem 1.8rem}
.menu-tax .menu-foot a{min-height:44px;display:inline-flex;align-items:center}
/* The tax site's only theme toggle (6 Oct 2026): the bar's icon left, so
   the menu's worded button shows at every width here; the rule below
   that hides it above 480px is the rentals menu's. */
.menu-tax .menu-theme{display:inline-block;margin-left:auto}
/* The question box (place-first navigation, Phase 5, 29 Sep 2026): on the
   Ohio page, Topics and its own page, and first in the tax menu. Its look
   lives here rather than in taxes.css because the menu is on pages that
   load only this file. */
.ask-form label{display:block;font-size:.82rem;letter-spacing:.06em;text-transform:uppercase;
  color:var(--text-soft);margin-bottom:.45rem}
.ask-row{display:flex;gap:.5rem}
.ask-row input{flex:1;min-width:0;padding:.85rem 1rem;border-radius:14px;
  border:1px solid var(--line);background:var(--surface-raise);color:var(--text-strong);
  font:inherit;font-size:1rem;min-height:3rem}
.ask-row input::placeholder{color:var(--text-softer)}
.ask-row input:focus-visible{outline:3px solid var(--fern-glow);outline-offset:2px}
.ask-row .btn{padding-inline:1.4rem}
/* The guide under every box (1 Oct 2026): a link, and the dialog it opens
   over the page (b/_ask_guide.html). Here for the same reason as the box:
   the menu that carries one is on pages that load only this file. The
   dialog has no padding of its own, so a tap on it is a tap on the
   backdrop, which closes it (js/place.js); its inner box scrolls. */
.ask-guide-line{margin:.55rem 0 0;font-size:.95rem;line-height:1.5}
.ask-guide-line a{color:var(--fern-light);text-decoration:underline;text-underline-offset:3px}
.ask-guide{margin:auto;padding:0;border:1px solid var(--line);border-radius:18px;
  background:var(--ink-soft);color:var(--text-strong);
  width:min(46rem,calc(100vw - 32px));max-width:none;max-height:min(88vh,56rem);overflow:hidden}
.ask-guide::backdrop{background:rgba(0,0,0,.6)}
.ask-guide-inner{padding:1.3rem 1.3rem 1.5rem;max-height:min(88vh,56rem);overflow-y:auto;
  overscroll-behavior:contain}
.ask-guide-head{display:flex;justify-content:space-between;align-items:center;gap:1rem}
.ask-guide-head h2{margin:0;font-size:1.5rem;font-weight:500;color:var(--text-strong)}
.ask-guide-head form{margin:0}
.ask-guide-x{font:inherit;font-size:1.6rem;line-height:1;width:2.75rem;height:2.75rem;flex:none;
  border-radius:50%;border:1px solid var(--line);background:none;color:var(--text-strong);cursor:pointer}
.ask-guide-x:hover{border-color:var(--fern-light)}
.ask-guide-lede{color:var(--text-soft);margin:.6rem 0 .4rem;max-width:40rem}
.ask-guide-group h3{font-size:.82rem;letter-spacing:.06em;text-transform:uppercase;font-weight:500;
  color:var(--text-softer);margin:1.15rem 0 .5rem}
.ask-guide-group ul{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:.5rem}
.ask-guide-group form{margin:0}
.ask-guide-note{font-size:.9rem;line-height:1.5;color:var(--text-softer);margin:1.3rem 0 0;max-width:40rem}
.ask-guide-inner > form:last-child{margin:1.4rem 0 0}
.ask-guide-page{max-width:46rem;margin:0 0 1.6rem}
/* A suggested question, as a pill: the Ask page's examples and the guide's. */
.ask-example{font:inherit;font-size:.95rem;color:var(--fern-light);background:none;cursor:pointer;
  border:1px solid var(--line);border-radius:999px;padding:.5rem .95rem;text-align:left;min-height:2.75rem}
.ask-example:hover{border-color:var(--fern-light)}
.ask-example:focus-visible,.ask-guide-x:focus-visible{outline:3px solid var(--fern-glow);outline-offset:2px}
.menu-ask{width:100%;max-width:40rem;margin:0 0 2rem;opacity:0;transform:translateY(28px);
  transition:opacity .5s var(--easing),transform .5s var(--easing)}
body.menu-open .menu-ask{opacity:1;transform:none}
.soon{font-size:.58rem;letter-spacing:.16em;text-transform:uppercase;
  border:1px solid var(--hair-dark);border-radius:999px;padding:.25rem .6rem;
  color:var(--muted-dark);vertical-align:middle;margin-left:.7rem;white-space:nowrap}

/* ================================ hero ================================== */
.hero{position:relative;min-height:100svh;display:flex;align-items:flex-end;
  overflow:hidden;background:var(--ink)}
.hero-media{position:absolute;inset:0}
/* Absolute + inset so the frames overlay each other; without this they stack
   down the page and only the first is ever in view. */
.hero-media img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;transition:opacity 1.6s var(--easing);will-change:opacity}
.hero-media img.is-active{opacity:1}
/* Slow drift keeps a still photo from feeling static. */
@keyframes drift{from{transform:scale(1.06) translate3d(0,0,0)}to{transform:scale(1.14) translate3d(0,-1.4%,0)}}
.hero-media img.is-active{animation:drift 18s ease-out forwards}
/* The first picture fades in once it has arrived (the user, 8 Oct 2026),
   rather than appearing whole on the dark stage a moment after the page.
   With script it is held at nothing until b.js marks the stage ready, then
   comes up over 1.2s, and its drift starts as it does. Failsafe like the
   banner's: a script that never acts leaves it showing after 2.5s, and a
   visitor without script sees it at once. Under reduced motion it simply
   appears when it has loaded. */
.js [data-hero]:not(.is-ready) img.is-active{opacity:0;animation:hero-failsafe 0s 2.5s forwards}
@keyframes hero-failsafe{to{opacity:1}}
.hero-media[data-hero].is-opening img{transition:opacity 1.2s ease-out}
/* Two scrims: vertical for the nav and the fade into the next section, plus a
   left-weighted one so the copy keeps contrast over a bright, busy photo.
   Without the horizontal pass, white text over pale siding failed AA. */
.hero::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:
    linear-gradient(180deg,rgba(17,17,16,.62) 0%,rgba(17,17,16,.26) 30%,rgba(17,17,16,.74) 74%,rgba(17,17,16,.96) 100%),
    linear-gradient(90deg,rgba(17,17,16,.78) 0%,rgba(17,17,16,.42) 44%,rgba(17,17,16,0) 76%)}
.hero-inner{position:relative;z-index:2;width:100%;color:var(--bone);
  padding-bottom:clamp(40px,7vw,90px)}
.hero h1{max-width:16ch;margin-bottom:1.5rem}
.hero .lede{color:var(--text-soft);max-width:min(44ch,100%);margin-bottom:2.4rem}
.hero-actions{display:flex;flex-wrap:wrap;gap:.8rem;align-items:center}
.btn{font-family:"Inter var",Inter,sans-serif;font-size:.92rem;font-weight:500;
  padding:1rem 2rem;border-radius:999px;display:inline-flex;align-items:center;gap:.6rem;
  transition:transform .35s var(--easing),background .3s,color .3s,border-color .3s;
  border:1px solid transparent;white-space:nowrap}
.btn:hover{transform:translateY(-2px)}
.btn-solid{background:var(--bone);color:var(--ink)}
.btn-solid:hover{background:var(--bone-hi)}
.btn-line{border-color:var(--text-faint);color:var(--bone)}
.btn-line:hover{background:var(--text-faint);border-color:var(--text-soft)}
.btn-dark{background:var(--ink);color:var(--bone)}
.btn-dark:hover{background:#2F6B4F;color:#FAF7F2}
.chip{display:inline-flex;align-items:center;gap:.7rem;margin-top:2.4rem;
  padding:.72rem 1.35rem;border-radius:999px;font-size:.82rem;letter-spacing:.02em;
  background:var(--text-faint);border:1px solid var(--text-faint);
  backdrop-filter:blur(10px);color:var(--text-strong)}
.dot{width:6px;height:6px;border-radius:50%;background:var(--fern-glow);flex-shrink:0}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
.chip .dot{animation:pulse 2.6s ease-in-out infinite}
/* hero photo pager */
.hero-pager{position:absolute;right:var(--pad);bottom:clamp(40px,7vw,90px);z-index:3;
  display:flex;flex-direction:column;gap:.55rem}
.hero-pager button{width:2px;height:26px;background:var(--text-faint);border-radius:2px;
  transition:background .4s,height .4s var(--easing)}
.hero-pager button[aria-current="true"]{background:var(--bone);height:40px}
.scroll-hint{position:absolute;left:var(--pad);bottom:clamp(18px,2.6vw,30px);z-index:3;
  font-size:.62rem;letter-spacing:.24em;text-transform:uppercase;color:var(--text-softer)}

/* ============================ section headers =========================== */
.sec-head{display:grid;grid-template-columns:1fr;gap:1.6rem;margin-bottom:clamp(38px,5.5vw,76px)}
@media(min-width:900px){
  .sec-head{grid-template-columns:1.35fr .85fr;align-items:end;gap:3rem}
  .sec-head .lede{justify-self:end;text-align:right}
}

/* ========================== property portfolio ========================== */
/* Photo-led cards. A rentals portfolio lives or dies on the photography, so
   the image carries the card and the type sits on a scrim over it — rather
   than hiding the home until hover. auto-fit keeps 3 homes and 30 both honest. */
/* Auto-scrolling rail. Four across on desktop, drifting left so the list
   advances in reading order.

   The track holds the list twice and shifts by exactly one list-length, so the
   loop is seamless. --pitch is one card plus one gap; card width is derived
   from it, so the travel distance and the card size can never disagree — which
   is what makes a marquee stutter at the seam. Percentages in both resolve
   against the same box (the track), so they stay locked together at any width.

   Divisors are literals rather than a var(), because dividing by a custom
   property in calc() is a newer capability than the rest of this file assumes.

   Under prefers-reduced-motion this becomes the static grid it replaced. It
   must NOT merely stop: a halted rail parks most of the portfolio off-screen
   behind hidden overflow, which is worse than never having moved. */
.props-rail{--gap:clamp(12px,1.1vw,18px);position:relative;overflow:hidden;
  -webkit-mask-image:linear-gradient(90deg,transparent 0,#000 3.5%,#000 96.5%,transparent 100%);
          mask-image:linear-gradient(90deg,transparent 0,#000 3.5%,#000 96.5%,transparent 100%)}
.props-track{--pitch:calc((100% + var(--gap)) / 1.15);
  display:flex;flex-wrap:nowrap;gap:var(--gap);
  animation:props-drift calc(var(--n,6) * 7s) linear infinite}
@media(min-width:640px){.props-track{--pitch:calc((100% + var(--gap)) / 2.2)}}
@media(min-width:1000px){.props-track{--pitch:calc((100% + var(--gap)) / 4)}}
.props-track > .prop{flex:0 0 calc(var(--pitch) - var(--gap))}
@keyframes props-drift{
  from{transform:translateX(0)}
  to{transform:translateX(calc(var(--n) * var(--pitch) * -1))}
}
/* Pause on hover and on focus — a keyboard user tabbing through cards should
   not be chasing a moving target. */
.props-rail:hover .props-track,
.props-rail:focus-within .props-track,
.props-rail[data-paused] .props-track{animation-play-state:paused}

.rail-pause{display:none;margin:1.2rem auto 0;align-items:center;gap:.55rem;
  background:none;border:1px solid var(--hair);color:var(--text-softer);
  border-radius:999px;padding:.44rem 1.05rem;font:inherit;font-size:.74rem;
  letter-spacing:.08em;text-transform:uppercase;cursor:pointer;
  transition:color .3s var(--easing),border-color .3s var(--easing)}
.js .rail-pause{display:flex}
.rail-pause:hover{color:var(--bone);border-color:var(--text-faint)}
.rail-pause-bars{width:8px;height:9px;border-inline:3px solid currentColor}
.rail-pause[aria-pressed="true"] .rail-pause-bars{
  width:0;height:0;border:5px solid transparent;border-left:8px solid currentColor}

@media(prefers-reduced-motion:reduce){
  .props-rail{overflow:visible;-webkit-mask-image:none;mask-image:none}
  .props-track{display:grid;animation:none;
    grid-template-columns:repeat(auto-fit,minmax(min(100%,320px),1fr))}
  .props-track > .prop{flex:none}
  .props-track > [aria-hidden="true"]{display:none}
  .rail-pause,.js .rail-pause{display:none}
}
.prop{position:relative;display:flex;align-items:flex-end;isolation:isolate;
  aspect-ratio:4/4.6;border-radius:18px;overflow:hidden;background:var(--ink-soft)}
.prop-photo{position:absolute;inset:0;z-index:0}
.prop-photo img{width:100%;height:100%;object-fit:cover;
  transform:scale(1.02);transition:transform 1.3s var(--easing)}
.prop:hover .prop-photo img,.prop:focus-within .prop-photo img{transform:scale(1.09)}
.prop-photo::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(17,17,16,.18) 0%,rgba(17,17,16,.10) 38%,
    rgba(17,17,16,.72) 76%,rgba(17,17,16,.94) 100%);
  transition:opacity .5s var(--easing)}
.prop-body{position:relative;z-index:2;width:100%;padding:clamp(1.1rem,1.6vw,1.6rem)}
.prop h3{margin-bottom:.15rem;color:var(--bone)}
.prop .where{font-size:.86rem;color:var(--text-softer);margin-bottom:.9rem}
.prop-meta{display:flex;flex-wrap:wrap;align-items:center;gap:.45rem;
  font-size:.79rem;color:var(--text-soft)}
.tag{font-family:"Inter var",Inter,sans-serif;font-size:.58rem;font-weight:500;
  letter-spacing:.14em;text-transform:uppercase;padding:.3rem .65rem;border-radius:999px;
  backdrop-filter:blur(8px);border:1px solid var(--edge)}
.tag.free{color:#0F2A1D;background:var(--fern-glow);border-color:transparent}
.tag.taken{color:var(--text-strong);background:rgba(17,17,16,.42)}
/* Status badge floats over the photo, top-left, like the A variant. */
.prop .tag-float{position:absolute;top:1rem;left:1rem;z-index:2}
.arrow{position:absolute;top:1rem;right:1rem;z-index:2;
  width:38px;height:38px;border-radius:50%;display:grid;place-items:center;font-size:.85rem;
  background:var(--text-faint);border:1px solid var(--edge);color:var(--bone);
  backdrop-filter:blur(8px);
  transition:background .35s,color .35s,transform .5s var(--easing)}
.prop:hover .arrow{background:var(--bone);color:var(--ink);transform:rotate(45deg)}
.prop-link{position:absolute;inset:0;z-index:3}

/* ============================ staircase steps =========================== */
.steps{display:flex;flex-direction:column;gap:clamp(10px,1.4vw,18px)}
.step{display:grid;gap:.4rem 2rem;align-items:start;
  padding:clamp(1.5rem,2.4vw,2.4rem);border:1px solid var(--hair-dark);border-radius:16px;
  background:var(--line-faint);
  grid-template-columns:auto 1fr;
  transition:background .45s var(--easing),border-color .45s var(--easing),transform .45s var(--easing)}
.step:hover{background:var(--line-faint);border-color:var(--edge)}
@media(min-width:900px){
  .step{grid-template-columns:auto 1fr auto;align-items:center}
  /* progressive indent — the cascade that gives the section its shape */
  .step:nth-child(2){margin-left:5%}
  .step:nth-child(3){margin-left:10%}
  .step:nth-child(4){margin-left:15%}
  .step:nth-child(5){margin-left:20%}
}
.step .num{font-size:.64rem;letter-spacing:.2em;color:var(--muted-dark);padding-top:.5rem}
.step h3{margin-bottom:.35rem}
.step p{font-size:.94rem;color:var(--muted-dark);max-width:min(52ch,100%)}
.step .fig{font-family:"Inter var",Inter,sans-serif;font-weight:300;letter-spacing:-.045em;
  font-size:clamp(1.9rem,3.4vw,3rem);line-height:1;text-align:right;grid-column:2;justify-self:start}
@media(min-width:900px){.step .fig{grid-column:auto;justify-self:end;text-align:right}}
.step .fig small{display:block;font-family:"Barlow",sans-serif;font-size:.66rem;font-weight:400;
  letter-spacing:.12em;text-transform:uppercase;color:var(--muted-dark);margin-top:.5rem}

/* ================================ stats ================================= */
.stats{display:grid;grid-template-columns:repeat(2,1fr);gap:1px;background:var(--hair);
  border-block:1px solid var(--hair)}
@media(min-width:900px){.stats{grid-template-columns:repeat(4,1fr)}}
.stat{background:var(--bone);padding:clamp(1.8rem,3.4vw,3rem) 1.2rem;text-align:center}
.stat .n{font-family:"Inter var",Inter,sans-serif;font-weight:300;letter-spacing:-.05em;
  font-size:clamp(2.4rem,5.2vw,4.4rem);line-height:1;display:block}
.stat .l{font-size:.76rem;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
  margin-top:.9rem;display:block}

/* ============================= testimonials ============================= */
.quotes{display:grid;gap:1.5rem}
@media(min-width:900px){.quotes{grid-template-columns:repeat(2,1fr);gap:2rem}}
.quote{padding:clamp(1.8rem,3vw,2.8rem);border:1px solid var(--hair);border-radius:18px;
  /* The card paints its own white, so it states its own text colour too. A
     custom property is resolved where it is USED: re-declaring --ink on .quote
     does nothing while `color` is inherited from body, because body already
     resolved it against the page's value. */
  background:#fff;color:var(--ink);display:flex;flex-direction:column;
  transition:transform .5s var(--easing),box-shadow .5s var(--easing)}
.quote:hover{transform:translateY(-4px);box-shadow:0 18px 50px rgba(17,17,16,.09)}
.quote blockquote{font-family:"Inter var",Inter,sans-serif;font-weight:300;
  font-size:clamp(1.05rem,1.7vw,1.4rem);line-height:1.45;letter-spacing:-.02em;
  margin-bottom:auto;padding-bottom:1.8rem}
.quote figcaption{font-size:.78rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--muted);padding-top:1.4rem;border-top:1px solid var(--hair)}
.stars{color:var(--fern);letter-spacing:.18em;font-size:.78rem;margin-bottom:1.4rem}

/* ============================== split CTA =============================== */
.split{display:grid;gap:1px;background:var(--hair-dark);
  border:1px solid var(--hair-dark);border-radius:20px;overflow:hidden}
@media(min-width:860px){.split{grid-template-columns:1fr 1fr}}
.split > div{background:var(--ink);padding:clamp(2rem,4vw,3.6rem);
  display:flex;flex-direction:column;transition:background .45s var(--easing)}
.split > div:hover{background:var(--ink-soft)}
.split h3{margin:.9rem 0 .7rem}
.split p{color:var(--muted-dark);font-size:.96rem;margin-bottom:2.4rem;max-width:min(42ch,100%)}
.split .btn{align-self:flex-start;margin-top:auto}

/* =============================== contact ================================ */
.contact{display:grid;gap:2.6rem}
@media(min-width:900px){.contact{grid-template-columns:1fr 1fr;gap:4rem}}
.field{margin-bottom:1rem}
.contact input,.contact textarea{width:100%;font:inherit;font-size:.98rem;color:var(--ink);
  background:#fff;border:1px solid var(--hair);border-radius:12px;padding:1rem 1.15rem;
  transition:border-color .3s,box-shadow .3s}
.contact textarea{min-height:140px;resize:vertical}
.contact input:focus,.contact textarea:focus{outline:none;border-color:var(--fern);
  box-shadow:0 0 0 3px rgba(47,107,79,.12)}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
.skip{position:absolute;left:-9999px;z-index:99;background:var(--ink);color:var(--bone);
  padding:.8rem 1.2rem;border-radius:0 0 10px 0;font-size:.9rem}
.skip:focus{left:0;top:0}
.flash{padding:.9rem 1.15rem;border-radius:12px;font-size:.92rem;margin-bottom:1.2rem}
.flash-success{background:#EAF3EE;color:#1F4C39;border:1px solid #B9D8C7}
.flash-error{background:#FBEDE8;color:#8C3D22;border:1px solid #E7C3B4}
.contact-lines{font-size:1rem;color:var(--muted);line-height:2}
.contact-lines a{border-bottom:1px solid var(--hair);transition:border-color .3s}
.contact-lines a:hover{border-color:var(--fern)}

/* ================================ footer ================================ */
.foot{background:var(--ink);color:var(--bone);padding-block:clamp(56px,7vw,96px) 2rem}
.foot-grid{display:grid;gap:2.6rem;margin-bottom:clamp(48px,7vw,88px)}
@media(min-width:820px){.foot-grid{grid-template-columns:2fr 1fr 1fr}}
.foot h4{font-size:.64rem;letter-spacing:.2em;text-transform:uppercase;color:var(--muted-dark);
  margin-bottom:1.3rem;font-weight:500}
.foot nav a{display:block;padding:.32rem 0;font-size:.94rem;color:var(--text-soft);
  transition:color .25s}
.foot nav a:hover{color:var(--bone)}
.foot .wordmark{font-size:clamp(1.9rem,3.4vw,2.7rem);margin-bottom:1rem}
.foot-blurb{color:var(--muted-dark);font-size:.94rem;max-width:min(34ch,100%)}
/* Oversized wordmark bleeding across the base — the sign-off. */
.foot-mark{font-family:"Inter var",Inter,sans-serif;font-weight:300;letter-spacing:-.05em;
  font-size:clamp(3rem,15.5vw,15rem);line-height:.82;color:var(--text-faint);
  white-space:nowrap;user-select:none;pointer-events:none;margin-bottom:1.4rem}
.foot-base{display:flex;flex-wrap:wrap;gap:.7rem 1.6rem;justify-content:space-between;
  padding-top:1.8rem;border-top:1px solid var(--hair-dark);
  font-size:.78rem;color:var(--muted-dark)}

/* ========================== scroll-reveal ============================== */
/* Gated on .js (set by an inline script in <head>). Without it the content is
   simply visible: a reveal animation must never be the reason a page is blank
   when scripting is unavailable or the observer never fires. */
.js [data-reveal]{opacity:0;transform:translateY(22px);
  transition:opacity .85s var(--easing),transform .85s var(--easing)}
.js [data-reveal].shown{opacity:1;transform:none}
.js [data-reveal-stagger] > *{opacity:0;transform:translateY(20px);
  transition:opacity .7s var(--easing),transform .7s var(--easing);
  transition-delay:calc(var(--i,0) * 70ms)}
.js [data-reveal-stagger].shown > *{opacity:1;transform:none}

@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important}
  .js [data-reveal],.js [data-reveal-stagger] > *{opacity:1;transform:none}
  .hero-media img.is-active{animation:none;transform:scale(1.04)}
}

/* Sign out in the full-screen menu, styled to match the links beside it. */
.menu-signout{display:inline}
.menu-signout button{background:none;border:none;padding:0;font:inherit;
  color:inherit;cursor:pointer;text-decoration:none}
.menu-signout button:hover{text-decoration:underline}


/* Theme toggle in the menu foot — the phone-width home for it. Above
   480px the nav pill has room and shows the icon button instead; exactly
   one of the two is ever visible, so there is no duplicate control. */
.menu-theme{background:none;border:1px solid var(--hair-dark);color:inherit;
  font:inherit;font-size:.86rem;border-radius:999px;padding:.4rem 1rem;
  cursor:pointer;transition:border-color .3s var(--easing)}
.menu-theme:hover{border-color:var(--edge)}
@media(min-width:480px){.menu-theme{display:none}}
@media(max-width:479px){.theme-btn{display:none}}

/* Photo surfaces are exempt from light mode: their text sits on the image's
   dark scrim, not on the page, so it must stay light-on-dark in both themes.
   Scoped token re-declarations — the components below read tokens, so this
   restores the dark rendering without touching a single rule. The Ohio
   page's scenes stage joined on 7 Oct 2026 (§27), and the picture viewer
   its caption opens the same day (§27.12). */
:root[data-theme="light"] .hero,
:root[data-theme="light"] .oh-stage,
:root[data-theme="light"] .pic-page,
:root[data-theme="light"] .nav-wrap.on-hero,
:root[data-theme="light"] .prop,
/* .pay-card belongs here for the same reason: it is a dark gradient panel,
   not a page surface, so its text has to stay light-on-dark in both themes.
   It was missing, which left the muted lines inside it dark-on-dark in light
   mode — barely visible before, and unreadable once the then-vs-now rows
   moved in and added four more. */
/* .readout is the same case again: it paints its own near-black #0E0E0D panel,
   so it is dark in both themes, but its text took var(--bone) and light mode
   flips that to near-black. Dark text on a near-black tooltip — the hover
   values were invisible on every chart. Third instance of this exact bug
   (.pay-card, .quote, now this), which is why there is a test below that
   fails for ANY fixed-dark surface missing from this list.

   Fourth instance, 8 Sep 2026: the announcement strip. It slipped past that
   test because it paints background:var(--fern), and the test skipped
   tokens on the reasoning that a token inverts with the page. --fern does
   not — it is declared once in :root and never restated for light — so it
   is a literal wearing a token's clothes, and the strip's text went
   near-black on dark green. The test now resolves tokens and skips only the
   ones light mode actually redefines. */
/* Fifth instance, 17 Sep 2026: the hub's figure panels. Same gradient as
   .pay-card, deliberately — the market overview's treatment was asked for
   on the hub's charts and tables because they blended into the page. The
   sweep below could not have caught it: it read `background:` with
   `.split()[0]`, so a linear-gradient parsed as nothing and EVERY gradient
   panel was invisible to it, .pay-card itself included. It reads gradient
   stops now. */
:root[data-theme="light"] .readout,
:root[data-theme="light"] .site-banner,
:root[data-theme="light"] .hub-panel,
/* The blog's tile and post hero are the same deliberate dark surfaces
   (21 Sep 2026): a card's tag and a post's title sit on a fixed gradient,
   so in light mode their text has to keep the dark theme's tokens or it
   inverts to near-black on near-black. The sweep below caught both. */
:root[data-theme="light"] .blog-card-tile,
:root[data-theme="light"] .blog-post-hero,
:root[data-theme="light"] .pay-card{
  --bone:#FAF7F2;
  --bone-hi:#FFFFFF;
  --ink:#111110;
  --ink-soft:#1A1A18;
  --muted:#6B6B63;
  --muted-dark:#8A8A80;
  --fern-light:#8FBCA4;
  --fern-glow:#A8D4BC;
  --warm:#E4B363;
  --star:#E4B363;
  --fall:#D98A72;
  --hair:rgba(17,17,16,.12);
  --hair-dark:var(--line);
  --surface-raise:rgba(26,26,24,.72);
  --text-strong:rgba(250,247,242,.92);
  --text-soft:rgba(250,247,242,.78);
  --text-softer:rgba(250,247,242,.62);
  --text-faint:rgba(250,247,242,.38);
  --edge-strong:rgba(255,255,255,.5);
  --edge:rgba(255,255,255,.26);
  --line:rgba(255,255,255,.13);
  --line-faint:rgba(255,255,255,.06);
}

/* Fields are hard-coded white too, and their text read var(--ink): in light
   mode that is near-paper, so what you typed into the contact form was pale
   on white. Same pin, same reason as .quote below. */
:root[data-theme="light"] .contact input,
:root[data-theme="light"] .contact textarea{
  --ink:#111110;
  --hair:rgba(17,17,16,.12);
}

/* The mirror case, and the other half of the same rule. .quote is hard-coded
   background:#fff, so it is a LIGHT surface in both themes — but light mode
   inverts the band around it to dark, and the card's text went with the band
   instead of with the card. The quotes were #F4F1EA on white: 1.13:1, i.e.
   invisible. Any surface with a fixed darkness needs the matching token set
   pinned to it, in whichever direction it is fixed. */
:root[data-theme="light"] .quote{
  --ink:#111110;
  --muted:#6B6B63;
  --hair:rgba(17,17,16,.12);
}


/* ------------------- the tax footer's topic buttons --------------------- */
/* The way back, at the bottom of the page. The tax pages are long — the
   reappraisal page is a map, six cards and a chart — so by the time a reader
   finishes one, the tab row at the top is several screens away, and this
   audience does not assume a wordmark is a link. Same list and the same
   words as the tabs (app/topics.py), so the two ends of the page cannot
   drift into calling one page two things.

   Styled here rather than in market.css because the tax footer renders on
   every page of that identity, including the legal pages, which do not load
   the market stylesheet. */
.foot .foot-topics{margin-bottom:2rem}
.foot .foot-topics h4{margin-bottom:.9rem}
.foot-topic-row{display:grid;gap:.6rem;
  grid-template-columns:repeat(auto-fit,minmax(15rem,1fr))}
.foot .foot-topics a{display:block;padding:.7rem .9rem;border-radius:10px;
  border:1px solid var(--hair-dark);text-decoration:none;
  transition:border-color .2s}
.foot .foot-topics a:hover{border-color:var(--text-faint)}
.foot .foot-topics .pg{display:block;font-size:.95rem;font-weight:600;
  color:var(--bone)}
.foot .foot-topics .blurb{display:block;font-size:.82rem;line-height:1.45;
  color:var(--muted-dark);margin-top:.1rem}
.foot .foot-topics a.is-home{border-color:var(--fern-light)}
.foot .foot-topics a.is-home .pg{color:var(--fern-light)}

/* Inside Facebook's, Messenger's or Instagram's own browser — the `in-app`
   class b/base.html's first script sets — hide what cannot work there:
   Google refuses to sign anyone in from an embedded browser. A class, not
   a server decision, because the pages that carry it are cached for every
   visitor alike (18 Sep 2026). */
.in-app .hide-in-app{display:none !important}

/* Your homes in the top bar (19 Sep 2026). A plain link like its neighbours
   for a stranger; for a browser that remembers a sign-in — `member`, from
   the first script — a filled button with a dot, which is the "you are
   signed in" every page used to lose. On a phone the bar's other links are
   hidden, so this shows there only for a member; a stranger has the menu. */
.nav-homes{font-size:.86rem;letter-spacing:.01em;opacity:.78;transition:opacity .25s;
  display:none;align-items:center;gap:.45rem;white-space:nowrap;margin-left:auto}
.nav-homes:hover{opacity:1}
.nav-homes-dot{display:none;width:.5rem;height:.5rem;border-radius:50%;background:#2F6B4F}
/* For a member only, at every width (6 Oct 2026): a stranger's "Saved
   checks" went into the menu with the rest of what is not the page. */
.member .nav-homes{display:inline-flex;opacity:1;background:var(--fern-glow);color:#111110;font-weight:600;
  padding:.45rem .95rem;border-radius:999px}
.member .nav-homes-dot{display:inline-block}
@media(max-width:900px){
  .member .nav-homes{font-size:.8rem;padding:.4rem .8rem}
}
/* The menu's footer offers one of the two, by the same memory. */
.for-member{display:none}
.member .for-member{display:inline}
.member .for-guest{display:none}

/* ===================== the Property Tax chrome ========================= */
/* Moved here from taxes.css on 22 Sep 2026, and the move is the point.
   The mark and the footer lockup are SITE chrome — base.html renders them
   on every page of the tax identity — but their rules lived in the
   SECTION stylesheet, which only the /market/taxes pages load. So on the
   other fourteen (the unpaid page, How Ohio compares, every zip, city,
   county, metro and state page, the tax 404) the wordmark rendered with no
   styling at all and read "Property TaxReport" on one line. Chrome's CSS
   belongs in the sheet the chrome is loaded with; tests/test_tax_chrome.py
   checks that by rendering pages and reading the sheets they actually
   link. */
/* ------------------------- the Property Tax mark (21 Sep 2026) ---------- */
/* A house whose inside is three rising bars, and a two-line lockup. The
   cursive .wordmark stays the rentals brand's; this is the tax identity's
   own, in the site's own Barlow. The glyph strokes currentColor, so the
   wrapper decides its colour per surface: deep fern on the grey bar (which
   is light in both themes), the glow token on the footer's ground. */
.brand-tax{display:inline-flex;text-decoration:none;color:inherit}
.wm-tax{display:inline-flex;align-items:center;gap:.55rem;line-height:1;white-space:nowrap}
.wm-glyph{flex:0 0 auto;color:#2F6B4F}
.wm-lines{display:inline-flex;flex-direction:column}
.wm-t{font-family:"Barlow",ui-sans-serif,system-ui,sans-serif;font-weight:600;
  font-size:1.06rem;letter-spacing:.005em}
.wm-s{font-family:"Barlow",ui-sans-serif,system-ui,sans-serif;font-weight:500;
  font-size:.62rem;letter-spacing:.2em;text-transform:uppercase;margin-top:.18rem;
  opacity:.72}
.wm-tax-nav .wm-glyph{width:1.55rem;height:1.55rem}
/* A hover underline like the script mark had, drawn under the lines only. */
.wm-lines{position:relative}
.wm-lines::after{content:"";position:absolute;left:50%;bottom:-.2rem;width:0;height:1.5px;
  transform:translateX(-50%);background:currentColor;opacity:.6;
  transition:width .45s var(--easing)}
.brand-tax:hover .wm-lines::after,.brand-tax:focus-visible .wm-lines::after{width:100%}
/* The footer sign-off: larger, on the footer's own ground, glyph in the
   glow token so it inverts with the theme like the text beside it. */
.tax-foot-mark{margin:0 0 1rem}
.wm-tax-foot{gap:.8rem}
.wm-tax-foot .wm-glyph{width:2.4rem;height:2.4rem;color:var(--fern-light)}
.wm-tax-foot .wm-t{font-size:1.5rem;color:var(--bone)}
.wm-tax-foot .wm-s{font-size:.8rem;color:var(--muted-dark);opacity:1}
@media (max-width:480px){
  .wm-tax-nav .wm-glyph{width:1.35rem;height:1.35rem}
  .wm-t{font-size:.98rem}
}
/* In the footer, `.tax-foot .foot-base span` flattens every span to a
   block with a 66ch measure — right for the credit line, wrong for the
   mark, which stacked into three rows. Restated at the footer's own
   specificity so the lockup keeps its shape. */
.tax-foot .foot-base .tax-foot-mark{flex:0 0 auto;margin:0}
.tax-foot .foot-base .wm-tax{display:inline-flex;max-width:none;line-height:1;color:var(--bone)}
.tax-foot .foot-base .wm-glyph{display:block}
.tax-foot .foot-base .wm-lines{display:inline-flex;max-width:none;line-height:1}
.tax-foot .foot-base .wm-t{display:block;max-width:none;line-height:1;font-size:1.5rem;color:var(--bone)}
.tax-foot .foot-base .wm-s{display:block;max-width:none;line-height:1;font-size:.8rem;color:var(--muted-dark)}
/* The same footer span rule was also showing BOTH labels of the member
   link at once — b.css's .for-member{display:none} is one class and lost
   to it. Restated here, both states. */
.tax-foot .foot-base .for-member{display:none}
.member .tax-foot .foot-base .for-member{display:inline}
.member .tax-foot .foot-base .for-guest{display:none}
