:root{
 --bg:#f0f2ed;--panel:#f8f7f1;--panel2:#e8ebe3;--ink:#181a17;--sub:#555a52;--muted:#858a80;
 --border:#d8dccf;--accent:#0f6e56;--accent-bg:#d9eee7;--warm:#b4530f;
 --mid:#e1e4da;--nodata:#dcdfd4;--mesh:rgba(20,22,20,.15);--prov:rgba(20,22,20,.32);
 --s1:#2a78d6;--s2:#1baf7a;--s3:#eda100;--s4:#008300;--s5:#4a3aa7;--s6:#e34948;--s7:#e87ba4;--s8:#eb6834;
}
@media (prefers-color-scheme:dark){:root{
 --bg:#131511;--panel:#1b1e1a;--panel2:#20241f;--ink:#eaeae2;--sub:#a6a99f;--muted:#787c72;
 --border:#2a2e28;--accent:#5dcaa5;--accent-bg:#123a30;--warm:#e08a4b;
 --mid:#33352e;--nodata:#21241e;--mesh:rgba(255,255,255,.12);--prov:rgba(255,255,255,.3);
 --s1:#3987e5;--s2:#199e70;--s3:#c98500;--s4:#008300;--s5:#9085e9;--s6:#e66767;--s7:#d55181;--s8:#d95926;
}}
:root[data-theme="dark"]{
 --bg:#131511;--panel:#1b1e1a;--panel2:#20241f;--ink:#eaeae2;--sub:#a6a99f;--muted:#787c72;
 --border:#2a2e28;--accent:#5dcaa5;--accent-bg:#123a30;--warm:#e08a4b;
 --mid:#33352e;--nodata:#21241e;--mesh:rgba(255,255,255,.12);--prov:rgba(255,255,255,.3);--s1:#3987e5;--s2:#199e70;--s3:#c98500;--s4:#008300;--s5:#9085e9;--s6:#e66767;--s7:#d55181;--s8:#d95926;}
:root[data-theme="light"]{
 --bg:#f0f2ed;--panel:#f8f7f1;--panel2:#e8ebe3;--ink:#181a17;--sub:#555a52;--muted:#858a80;
 --border:#d8dccf;--accent:#0f6e56;--accent-bg:#d9eee7;--warm:#b4530f;
 --mid:#e1e4da;--nodata:#dcdfd4;--mesh:rgba(20,22,20,.15);--prov:rgba(20,22,20,.32);--s1:#2a78d6;--s2:#1baf7a;--s3:#eda100;--s4:#008300;--s5:#4a3aa7;--s6:#e34948;--s7:#e87ba4;--s8:#eb6834;}
*{box-sizing:border-box}
html{color-scheme:light dark}
:root[data-theme="dark"]{color-scheme:dark}
:root[data-theme="light"]{color-scheme:light}
/* The sans stack was declared only on .wrap/.hero/.rsApp, so anything outside those
   (and any new template) inherited the browser's default serif. Set it at the root. */
html,body{margin:0;background:var(--bg);color:var(--ink);
 font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif}
.wrap{max-width:1000px;margin:0 auto;padding:2.2rem 1.25rem 4rem;color:var(--ink);
 font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;line-height:1.6}
.eyebrow{font-size:12px;letter-spacing:.16em;text-transform:uppercase;color:var(--accent);font-weight:600;margin:0 0 .5rem}
h1{font-size:34px;line-height:1.1;font-weight:600;margin:0 0 .6rem;letter-spacing:-.02em;text-wrap:balance}
h2{font-size:21px;font-weight:600;margin:0 0 .3rem;letter-spacing:-.01em}
.lede{font-size:17px;color:var(--sub);margin:0 0 .4rem;max-width:64ch}
.lede b{color:var(--ink);font-weight:600}

/* ---------- Homepage hero: the dataset as the banner ----------
   The background is a real Natural Earth map (same world_topo.json the page
   already ships), pre-rendered into index.html by geomax/build_hero.py: a dot
   grid for land, a denser accent grid for the 20 live markets, and one circle
   per city at its true lat/lng - area by population, fill by its male-to-female
   ratio on the SHARED 94/100/112 ramp (RATIO_DOMAIN in js/common.js).
   home.js repaints the same circles when the age band changes; the Sweep/Hold
   toggle animates the band. Rerun build_hero.py after any cities.json change. */
.hero{position:relative;isolation:isolate;overflow:hidden;min-height:clamp(360px,52vh,540px);display:flex;align-items:flex-end;border-bottom:1px solid var(--border);margin-top:0;padding-top:0;border-top:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif}
.hero+.wrap{padding-top:1.5rem}
.hero+.wrap>section:first-child{margin-top:0;border-top:0;padding-top:0}
.heroMedia{position:absolute;inset:0;z-index:-1}
.heroSky{position:absolute;inset:0;background:
 radial-gradient(120% 120% at 76% 8%,color-mix(in srgb,var(--accent) 13%,var(--bg)),transparent 58%),
 linear-gradient(180deg,var(--panel2),var(--bg) 72%)}
.heroWorld{position:absolute;inset:0;width:100%;height:100%}
/* Land: a dot grid, so the map reads as a measuring instrument rather than a
   filled illustration. Live markets get a denser, accented grid. */
.heroWorld #hwGrid circle{fill:var(--ink);opacity:.17}
.heroWorld #hwGridLive circle{fill:var(--accent);opacity:.52}
.hwLand{fill:url(#hwGrid)}
.hwLive{fill:url(#hwGridLive)}
.hwGrat{fill:none;stroke:var(--mesh);stroke-width:.7;opacity:.55;vector-effect:non-scaling-stroke}
/* One circle per city. --q is the position on the ramp, baked per city by
   build_hero.py; the fill attribute is the light-theme fallback for browsers
   without color-mix. .hi is the 100->112 (red) half of the ramp. .hwOff is a city
   outside the region the tour is holding on. */
.hwCities circle{fill:color-mix(in srgb,var(--mid) calc(var(--q,0) * 100%),#1d9e75);
 stroke:color-mix(in srgb,var(--bg) 62%,transparent);stroke-width:.7;
 vector-effect:non-scaling-stroke;transition:opacity .5s ease}
.hwCities circle.hi{fill:color-mix(in srgb,#c0392b calc(var(--q,0) * 100%),var(--mid))}
.hwCities circle.nd{fill:var(--nodata);opacity:.7}
.hwCities circle.hwOff{opacity:.2}
/* Zoom is a transform on .hwZoom driven by home.js (rAF, not a CSS transition -
   the same frame has to counter-scale the dots, the land grid and the labels). */
.hwZoom{will-change:transform}
.hwLabels{transition:opacity .35s ease}
.hwLabels.hwMoving{opacity:0}
.hwLabel line{stroke:var(--ink);opacity:.32;stroke-width:1;vector-effect:non-scaling-stroke}
.hwLabel text{font-size:12.5px;font-weight:600;fill:var(--ink);opacity:.85;letter-spacing:.005em}
.hwLabel text.v{font-size:11.5px;fill:var(--sub);font-variant-numeric:tabular-nums;opacity:.95}
/* HTML, not SVG: the map viewBox is cropped (slice) at desktop aspect ratios and
   an in-SVG legend gets cut off. z-index lifts it over the scrim. */
.hwLegend{position:absolute;right:1.25rem;bottom:1.1rem;z-index:2;text-align:right;pointer-events:none}
.hwLegend p{margin:0}
.hwlHead{font-size:11px;letter-spacing:.09em;text-transform:uppercase;font-weight:600;color:var(--sub)}
/* The tour's readout: the region's aggregate for the current band. */
.hwlVal{font-size:12px;color:var(--muted);margin-top:.1rem!important}
.hwlVal b{font-size:23px;font-weight:650;color:var(--ink);font-variant-numeric:tabular-nums;
 letter-spacing:-.01em;margin-right:.28rem}
.hwlBar{height:7px;border-radius:4px;margin:.35rem 0 .25rem;
 background:linear-gradient(90deg,#1d9e75,var(--mid) 33%,#c0392b)}
.hwlTicks{display:flex;justify-content:space-between;font-size:10.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.hwlFoot{font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums;margin-top:.3rem!important}
/* Readability scrim: tinted with the page background, not black, so the copy
   keeps theme contrast in both light and dark. */
.heroScrim{position:absolute;inset:0;background:
 linear-gradient(0deg,color-mix(in srgb,var(--bg) 93%,transparent) 0%,color-mix(in srgb,var(--bg) 62%,transparent) 30%,color-mix(in srgb,var(--bg) 12%,transparent) 62%,transparent 84%),
 radial-gradient(90% 78% at 16% 92%,color-mix(in srgb,var(--bg) 72%,transparent),transparent 62%)}
.heroContent{max-width:1000px;width:100%;margin:0 auto;padding:2.6rem 1.25rem 2.2rem}
.hero .eyebrow{margin-bottom:.55rem}
.hero h1{font-size:clamp(30px,4.4vw,46px);max-width:20ch}
.hero .lede{color:var(--sub);max-width:56ch}
.hero .lede b{color:var(--ink)}
.heroToggle{position:absolute;top:1rem;right:1.25rem;z-index:2;backdrop-filter:blur(6px);background:color-mix(in srgb,var(--panel) 70%,transparent)}
/* Cropped hard on phones: the annotations would land on top of the copy. */
@media (max-width:900px){.hwLabels{display:none}}
/* Phones fit the whole map to the top (xMidYMin meet, set in index.html); the copy
   clears it via the .heroContent padding in the main mobile block further down. */
@media (max-width:640px){.hwLegend{display:none}
 .heroScrim{background:
 linear-gradient(0deg,color-mix(in srgb,var(--bg) 95%,transparent) 0%,color-mix(in srgb,var(--bg) 74%,transparent) 44%,color-mix(in srgb,var(--bg) 34%,transparent) 78%,transparent)}}
@media (prefers-reduced-motion:reduce){.hero *{animation:none!important;transition:none!important}}
section{margin-top:2.6rem;padding-top:2rem;border-top:1px solid var(--border)}
.shead{margin-bottom:1rem}
/* The orienting paragraph under the hero on guide pages. Bigger than body copy and
   measure-capped: at 1000px wide, 14px text runs ~140 characters a line. */
.seoLede{font-size:17px;line-height:1.62;color:var(--ink);max-width:68ch;margin:.2rem 0 1.5rem}
.seoLede b{font-weight:650;font-variant-numeric:tabular-nums}
/* Dating-age ratio block on the city guide pages. */
.seoRatioMore{margin:.6rem 0 0}
.seoRatioMore a{color:var(--accent);font-weight:600;text-decoration:none}
.seoRatioMore a:hover{text-decoration:underline}
.seoRatioNote{font-size:13px;color:var(--muted);margin:.5rem 0 0}
.sheadTop{display:flex;justify-content:space-between;align-items:flex-start;gap:12px}
.shead p{font-size:15.5px;color:var(--muted);margin:.25rem 0 0;max-width:66ch;line-height:1.55}
.toggleBtn{appearance:none;border:1px solid var(--border);background:var(--panel);color:var(--sub);font:inherit;font-size:12px;padding:.34rem .68rem;border-radius:999px;cursor:pointer;white-space:nowrap}
.toggleBtn:hover{background:var(--panel2);color:var(--ink)}
.toggleBtn:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.card{background:var(--panel);border:1px solid var(--border);border-radius:14px;padding:1rem}
.skelStatus{font-size:12px;color:var(--muted);margin:0 0 .65rem}
.skelGrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(215px,1fr));gap:12px}
.skelCard{display:grid;gap:.65rem;min-height:220px;border:1px solid var(--border);border-radius:14px;background:var(--panel);padding:1rem}
.skelCard.compact{min-height:150px}
.skelBlock,.skelLine{display:block;border-radius:8px;background:linear-gradient(90deg,var(--panel2),var(--mid),var(--panel2));background-size:220% 100%;animation:skelWash 1.15s ease-in-out infinite}
.skelBlock{height:70px}
.skelLine{height:12px}
.skelLine.short{width:45%}
.skelLine.mid{width:68%}
.skelLine.long{width:88%}
.skelRows{display:grid;gap:.45rem}
.skelTable{display:grid;gap:.45rem;width:100%;min-width:0}
.skelRow{display:grid;grid-template-columns:44px minmax(80px,1.4fr) minmax(64px,1fr) repeat(4,minmax(38px,.7fr));gap:.5rem;align-items:center}
.tableSkelRow th,.tableSkelRow td{height:42px;vertical-align:middle}
.tableSkelRow .skelLine{margin:0 auto}
.tableSkelRow th .skelLine{margin-left:0}
.skelMap{aspect-ratio:16/9;min-height:260px;border:1px solid var(--border);border-radius:12px;background:var(--panel2);overflow:hidden}
.skelPanel{display:grid;gap:.7rem}
@keyframes skelWash{0%{background-position:180% 0}100%{background-position:-80% 0}}
@media (prefers-reduced-motion:reduce){.skelBlock,.skelLine{animation:none}}
@media (max-width:640px){.skelRow{grid-template-columns:1fr 1fr}.skelRow .skelLine:nth-child(n+5){display:none}}
.controls{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:.8rem}
.seg{display:inline-flex;border:1px solid var(--border);border-radius:9px;overflow:hidden;background:var(--panel)}
.seg button{appearance:none;border:0;background:transparent;color:var(--sub);font:inherit;font-size:12.5px;padding:.42rem .72rem;cursor:pointer}
.seg button.on{background:var(--accent-bg);color:var(--accent);font-weight:600}
.seg button:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.legend{display:flex;align-items:center;gap:7px;font-size:11.5px;color:var(--sub);flex-basis:100%;margin-top:3px}
.ramp{height:11px;width:130px;border-radius:3px}
.rampStep{display:flex;height:11px;width:130px;border-radius:3px;overflow:hidden}
.rampStep i{flex:1;display:block}
.agerange{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--sub)}
.agerange select{font:inherit;font-size:13px;padding:.32rem .45rem;border:1px solid var(--border);border-radius:8px;background:var(--panel);color:var(--ink);cursor:pointer}
.agerange select:focus-visible{outline:2px solid var(--accent);outline-offset:-1px}
.btnSpin{display:inline-block;width:11px;height:11px;margin-right:5px;vertical-align:-1px;border:2px solid currentColor;border-top-color:transparent;border-radius:50%;animation:btnSpin .7s linear infinite}
@keyframes btnSpin{to{transform:rotate(360deg)}}
#wFlightsToggle[disabled]{opacity:.75;cursor:progress}
.ptselMap{display:inline-flex;align-items:center;gap:6px;font-size:12.5px;color:var(--sub)}
.ptselMap select{max-width:160px}
.ageSlider{display:grid;grid-template-columns:auto minmax(210px,280px);gap:6px 10px;align-items:center;font-size:13px;color:var(--sub)}
.ageSlider b{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
.dualRange{display:grid;grid-template-columns:26px 1fr 32px;gap:7px;align-items:center;color:var(--muted);font-size:11.5px}
.dualTrack{position:relative;height:26px;display:flex;align-items:center}
.dualTrack:before{content:"";position:absolute;z-index:0;left:0;right:0;top:50%;transform:translateY(-50%);height:4px;border-radius:4px;background:var(--panel2);border:1px solid var(--border);box-sizing:border-box}
.dualTrack input{position:absolute;z-index:1;inset:0;width:100%;height:100%;margin:0;padding:0;background:transparent;pointer-events:none;appearance:none;-webkit-appearance:none}
.dualTrack input:focus,.dualTrack input:active{z-index:2}
/* Set by dualZ() in research.js: raises whichever handle sits in the far half so two
   collided thumbs never trap each other (min dragged fully right used to be
   ungrabbable). Beats the :focus/:active rule above, which is why it is 3, not 2. */
.dualTrack input.onTop{z-index:3}
.dualTrack input[type=range]::-webkit-slider-thumb{position:relative;z-index:3;appearance:none;-webkit-appearance:none;width:15px;height:15px;margin-top:-6px;border-radius:50%;background:var(--accent);border:2px solid var(--panel);box-shadow:0 1px 4px rgba(0,0,0,.24);pointer-events:auto;cursor:pointer}
.dualTrack input[type=range]::-moz-range-thumb{position:relative;z-index:3;appearance:none;width:15px;height:15px;border-radius:50%;background:var(--accent);border:2px solid var(--panel);box-shadow:0 1px 4px rgba(0,0,0,.24);pointer-events:auto;cursor:pointer}
.dualTrack input[type=range]::-webkit-slider-runnable-track{height:4px;background:transparent;border:0}
.dualTrack input[type=range]::-moz-range-track{height:4px;background:transparent;border:0}
.maprow{display:grid;grid-template-columns:1fr;gap:14px}
@media(min-width:760px){.maprow{grid-template-columns:1.55fr 1fr}}
/* Themed surface (not inverted) so the tooltip stays dark in dark mode / light in
   light mode instead of flipping to a white box on the dark page. The hover
   pyramid's currentColor bars track --ink, so they still contrast --panel. */
#tip,#ptip{position:absolute;pointer-events:none;opacity:0;transform:translate(-50%,-118%);background:var(--panel);color:var(--ink);border:1px solid var(--border);box-shadow:0 4px 14px rgba(0,0,0,.18);
 font-size:12px;padding:6px 9px;border-radius:7px;white-space:nowrap;font-variant-numeric:tabular-nums;transition:opacity .08s;z-index:5}
/* ---- generic country deep-dive (country.js) ---- */
#ctyTip{position:absolute;display:none;pointer-events:none;background:var(--panel);color:var(--ink);border:1px solid var(--border);box-shadow:0 4px 14px rgba(0,0,0,.18);
 font-size:12px;padding:6px 9px;border-radius:7px;white-space:nowrap;font-variant-numeric:tabular-nums;z-index:5}
.ctyDetHead{font-size:16px;margin-bottom:.5rem}
.ctyDetStats{display:grid;grid-template-columns:1fr 1fr;gap:.5rem .8rem;margin-bottom:.6rem}
.ctyDetStats>div{display:flex;flex-direction:column;gap:1px}
.ctyDetStats .k{font-size:11px;color:var(--muted)}
.ctyDetStats .v{font-size:18px;font-weight:600;font-variant-numeric:tabular-nums}
.ctyMini{display:grid;gap:2px}
.ctyMiniRow{display:grid;grid-template-columns:44px 1fr;gap:6px;align-items:center;opacity:.5}
.ctyMiniRow.on{opacity:1}
.ctyMiniAge{font-size:10.5px;color:var(--muted);text-align:right;font-variant-numeric:tabular-nums}
.ctyMiniBars{display:flex;justify-content:center;height:9px;background:transparent}
/* Bar segments, centre-outwards: [M surplus][M base]|[W base][W surplus]. The base
   is the count both sexes share (pale); the surplus is the excess of whichever sex
   leads (saturated, at the tip). Same palette as the national .pyrBar pyramid. */
.ctyMiniM,.ctyMiniW,.ctyMiniMb,.ctyMiniWb{height:100%;align-self:center}
.ctyMiniM{background:#2f5f96}
.ctyMiniW{background:var(--warm,#c60)}
.ctyMiniMb{background:rgba(140,165,200,.5)}
.ctyMiniWb{background:rgba(210,165,120,.42)}
/* ---- admin mini-view tabs + A/B table ---- */
.adminTabs{display:flex;gap:.4rem;margin:0 0 1rem;flex-wrap:wrap}
.adminTab{padding:.4rem .85rem;border:1px solid var(--border);background:var(--panel);color:var(--ink);border-radius:8px;cursor:pointer;font-size:14px}
.adminTab.on{background:var(--accent,#0f6e56);color:#fff;border-color:transparent}
.abTable{width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums;font-size:13.5px}
.abTable th,.abTable td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--border);white-space:nowrap}
.abTable th{color:var(--muted);font-weight:600;font-size:12px}
.abTable tr.abBest td{background:hsl(150 58% 45% / .12)}
.abVerdict{margin-top:.7rem}
.detail h3{margin:0 0 .1rem;font-size:17px}
.detail .iso{color:var(--muted);font-size:12px;font-weight:400}
.drow{display:flex;justify-content:space-between;gap:10px;padding:.4rem 0;border-bottom:1px solid var(--border);font-size:13.5px}
.drow:last-child{border-bottom:0}
.drow .k{color:var(--sub)}
.drow .v{font-weight:600;font-variant-numeric:tabular-nums}
.read{font-size:13px;color:var(--sub);margin:.7rem 0 0;background:var(--panel2);border-radius:9px;padding:.6rem .7rem}
.ptsel{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13px;color:var(--sub);margin:0 0 .9rem;min-width:0}
.ptsel select{font:inherit;font-size:13px;padding:.4rem .5rem;border:1px solid var(--border);border-radius:8px;background:var(--panel);color:var(--ink);max-width:100%;min-width:0}
.ptsel select:focus-visible{outline:2px solid var(--accent);outline-offset:-1px}
.indexControls{display:flex;gap:14px 18px;align-items:center;justify-content:flex-start;flex-wrap:wrap;margin-bottom:.9rem}
.indexControls .ptsel{margin:0}
.visaStep{display:grid;grid-template-columns:auto 120px minmax(86px,auto);gap:8px;align-items:center;font-size:13px;color:var(--sub)}
.visaStep span{color:var(--accent);font-weight:600;font-variant-numeric:tabular-nums}
.sliders{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:14px 20px;margin-bottom:1rem}
.slab{display:flex;flex-direction:column;gap:2px}
.slab .top{display:flex;justify-content:space-between;font-size:13px}
.slab .top b{font-weight:600}.slab .top span{color:var(--accent);font-variant-numeric:tabular-nums}
.budgetRow{margin:0}
.indexControls .budgetRow{order:-1;flex:0 1 360px;max-width:100%}
/* Dual-thumb budget control stays deliberately compact beside its label. */
.budgetSlab{border:1px solid var(--border);background:var(--panel2);border-radius:10px;padding:.55rem .75rem;grid-template-columns:auto minmax(150px,200px)}
.indexControls .budgetSlab{width:100%;box-sizing:border-box}
.budgetSlab>span{font-size:14px}
.budgetSlab .top{font-size:14px}.budgetSlab .top b{color:var(--ink)}
input[type=range]{width:100%;accent-color:var(--accent);appearance:none;-webkit-appearance:none;background:transparent;height:15px;margin:0}
input[type=range]::-webkit-slider-runnable-track{height:4px;border-radius:4px;background:var(--panel2);border:1px solid var(--border)}
input[type=range]::-moz-range-track{height:4px;border-radius:4px;background:var(--panel2);border:1px solid var(--border)}
input[type=range]::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;width:15px;height:15px;margin-top:-6px;border-radius:50%;background:var(--accent);border:2px solid var(--panel);box-shadow:0 1px 4px rgba(0,0,0,.24);cursor:pointer}
input[type=range]::-moz-range-thumb{appearance:none;width:15px;height:15px;border-radius:50%;background:var(--accent);border:2px solid var(--panel);box-shadow:0 1px 4px rgba(0,0,0,.24);cursor:pointer}
.a3Slice{display:flex;flex-direction:column;gap:3px;font-size:12.5px;min-width:150px;flex:1 1 150px;max-width:230px}
.a3Slice>span{display:flex;gap:6px;align-items:center;color:var(--sub)}
.a3Slice>span b{color:var(--accent);font-variant-numeric:tabular-nums;font-weight:600}
table{width:100%;border-collapse:collapse;font-size:13.5px}
th,td{text-align:right;padding:.5rem .6rem;border-bottom:1px solid var(--border);font-variant-numeric:tabular-nums}
th:nth-child(2),td:nth-child(2){text-align:left}
#phlcities th:first-child,#phlcities td:first-child,#ctyCities th:first-child,#ctyCities td:first-child{text-align:left}
th{color:var(--muted);font-weight:500;font-size:11.5px;text-transform:uppercase;letter-spacing:.05em;cursor:default}
th[data-sort]{cursor:pointer;user-select:none}
th[data-sort]:hover,th.sortOn{color:var(--accent)}
th.sortOn:after{content:"";display:inline-block;margin-left:5px;border-left:4px solid transparent;border-right:4px solid transparent;vertical-align:middle}
th.sortOn[data-dir="asc"]:after{border-bottom:6px solid currentColor}
th.sortOn[data-dir="desc"]:after{border-top:6px solid currentColor}
tbody tr{cursor:pointer}
tbody tr:hover{background:var(--panel2)}
.idx{font-weight:600;color:var(--accent)}
.pill{display:inline-block;padding:1px 7px;border-radius:20px;font-size:11px;font-weight:600}
.note{font-size:13px;color:var(--muted);max-width:72ch;line-height:1.65}
.note b{color:var(--sub);font-weight:600}
.disc{margin-top:.6rem;font-size:12.5px;color:var(--warm)}
path{stroke-linejoin:round}
.mapbox{position:relative;background:var(--panel);border:1px solid var(--border);border-radius:14px;padding:.4rem;aspect-ratio:440/600}
.maptools{position:absolute;right:.65rem;top:.65rem;display:flex;gap:4px;z-index:4}
.maptools button{appearance:none;border:1px solid var(--border);background:var(--panel);color:var(--ink);width:28px;height:28px;border-radius:7px;font:600 15px/1 ui-sans-serif,system-ui;cursor:pointer;box-shadow:0 1px 5px rgba(0,0,0,.08)}
.maptools button:hover{background:var(--panel2)}
.maptools button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
/* Deep-dive map box. Was an inline style="max-width:520px" on the element, which
   capped the map at 520px on every screen — a 1440px desktop got the same postage
   stamp as a phone. The SVG's viewBox now follows the country's own aspect (see
   country.js buildMap), so the box no longer needs a fixed aspect-ratio either: it
   takes its height from the SVG. Full width of its column, no cap. */
.mapboxFluid{max-width:none;margin:0;aspect-ratio:auto;padding:.6rem}
/* Height ceiling. With an aspect-true viewBox a TALL country would otherwise render
   taller than the screen — Argentina and Vietnam both clamp to 520x780, which at an
   832px-wide panel is a 1248px-tall map you have to scroll to see. Capping the height
   lets the SVG's own preserveAspectRatio letterbox it sideways instead, which is what
   a tall country looks like on a wide screen anyway. Wide countries never hit this. */
.mapboxFluid #ctyMap svg{max-height:76vh;margin:0 auto}
.phgrid{display:grid;grid-template-columns:1fr;gap:14px;align-items:start}
@media(min-width:860px){.phgrid{grid-template-columns:minmax(0,1.25fr) minmax(260px,.75fr)}}
/* Wide desktops: give the map more of the row. The detail panel only needs ~300px to
   read comfortably, so past 1200px the extra width is better spent on the map. */
@media(min-width:1200px){.phgrid{grid-template-columns:minmax(0,1.6fr) minmax(300px,.7fr)}}
/* Phones: the map is the content, so let it use the full page width — cancel the
   panel padding and the wrap's side padding that would otherwise inset it twice. */
@media(max-width:640px){
 .mapboxFluid{padding:.3rem;border-radius:10px;margin-left:-.35rem;margin-right:-.35rem}
}
/* Wide desktops: the map panel breaks OUT of .wrap's 1000px cap. Every other panel is
   text and reads badly past ~1000px, so the wrap stays as-is and only this one widens
   — the map is the single element that genuinely benefits from the pixels.
   calc(100vw - 4rem) keeps it clear of the scrollbar (100vw includes it on Windows),
   and transform does not affect layout, so nothing else on the page shifts. */
@media(min-width:1280px){
 #panel-map .secPanelBody{width:min(1240px,calc(100vw - 4rem));margin-left:50%;transform:translateX(-50%)}
}
.cityDigestGrid{display:grid;grid-template-columns:1fr;gap:16px;margin-top:1rem}
@media(min-width:980px){.cityDigestGrid{grid-template-columns:repeat(2,minmax(0,1fr))}}
.cityDigestCol{min-width:0}
.cityCtxLead{margin:0 0 .85rem;max-width:76ch}
.cityCtxGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}
.cityCtxCard{background:var(--panel2);border:1px solid var(--border);border-radius:12px;padding:.8rem .9rem}
.cityCtxHead{display:flex;align-items:center;gap:.45rem;flex-wrap:wrap;font-size:15px}
.cityCtxWord{color:var(--sub);font-size:12.5px}
.cityCtxBig{display:block;margin-top:.45rem;font-size:26px;line-height:1.05;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.cityCtxBig small{font-size:13px;color:var(--muted);font-weight:500}
.cityCtxSub{display:block;margin-top:.12rem;font-size:13px;color:var(--sub);font-variant-numeric:tabular-nums}
.cityCtxFine{margin:.45rem 0 0;font-size:12.5px;color:var(--muted);line-height:1.55}
.citySignalLead{margin:0 0 .85rem;max-width:78ch}
.citySignalWrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.citySignalTable{min-width:820px;border-collapse:separate;border-spacing:0;width:100%}
.citySignalTable th,.citySignalTable td{padding:.5rem .55rem;border-bottom:1px solid var(--border);vertical-align:middle;text-align:left}
.citySignalTable thead th{font-size:11.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;font-weight:500;background:var(--panel);white-space:nowrap}
.citySignalTable tbody th{width:170px;color:var(--sub);font-size:12px;font-weight:600;cursor:help}
.citySignalCell{display:block;border-radius:10px;padding:.48rem .58rem;min-height:56px}
.citySignalMini{min-height:auto;padding:.4rem .5rem}
.citySignalCell b{display:block;color:var(--ink);font-size:13px;font-weight:700;font-variant-numeric:tabular-nums;line-height:1.25}
.citySignalCell span{display:block;margin-top:.16rem;color:var(--sub);font-size:11.5px;line-height:1.4}
.citySignalDim{color:var(--muted);font-size:11.5px}
.citySignalSources{margin:.8rem 0 0}
.countryOnlyCell{text-align:center;color:var(--muted)}
.countryRow td{background:color-mix(in srgb,var(--panel2) 72%, transparent)}
.countryRow:hover td{background:color-mix(in srgb,var(--panel2) 72%, transparent)}
#phlcities,#ctyCities{border-collapse:separate;border-spacing:0;width:max-content;min-width:100%}
.phMatrixScroll{overflow:auto;max-height:calc(100vh - 132px);max-height:calc(100dvh - 132px);-webkit-overflow-scrolling:touch}
@media (max-width:640px){.phMatrixScroll{max-height:calc(100vh - 96px);max-height:calc(100dvh - 96px)}}
#phlcities th,#phlcities td,#ctyCities th,#ctyCities td{text-align:center}
#phlcities th:first-child,#phlcities td:first-child,#ctyCities th:first-child,#ctyCities td:first-child{text-align:left}
#phlcities tbody tr,#ctyCities tbody tr{cursor:default}
#phlcities tbody tr:hover,#ctyCities tbody tr:hover{background:transparent}
#phlcities thead th,#ctyCities thead th{position:sticky;top:0;z-index:4;vertical-align:bottom;background:var(--panel);box-shadow:inset 0 -1px 0 var(--border)}
#phlcities thead th:first-child,#ctyCities thead th:first-child{left:0;z-index:5}
#phlcities tbody th,#ctyCities tbody th{position:sticky;left:0;z-index:2;background:var(--panel);color:var(--muted);box-shadow:inset -1px 0 0 var(--border)}
.phMatrixHead{display:flex;flex-direction:column;align-items:flex-start;gap:8px;min-width:clamp(94px,15vw,126px)}
.phMatrixHead b{display:block;color:var(--ink);font-size:14px;line-height:1.2}
.phMatrixHead .pill{margin-left:0}
.phMatrixCityBtn{appearance:none;border:0;background:none;color:var(--ink);font:inherit;font-size:14px;font-weight:700;padding:0;cursor:pointer;text-align:left}
.phMatrixCityBtn:hover{color:var(--accent);text-decoration:underline}
.phMatrixMetric{width:clamp(122px,18vw,160px);min-width:clamp(122px,18vw,160px)}
#ctyCities .phMatrixMetric,#ctyCities tbody th[scope="row"]{width:clamp(132px,24vw,220px);min-width:clamp(132px,24vw,220px);white-space:nowrap}
@media (max-width:640px){
 #phlcities th,#phlcities td,#ctyCities th,#ctyCities td{padding:.46rem .48rem}
 .phMatrixHead{min-width:88px;gap:6px}
 .phMatrixMetric{width:116px;min-width:116px}
 #ctyCities .phMatrixMetric,#ctyCities tbody th[scope="row"]{width:124px;min-width:124px;max-width:124px;overflow:hidden;text-overflow:ellipsis}
}
.phMatrixNa{color:var(--muted)}
.phMatrixMain{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.phsearch{display:flex;gap:6px;align-items:center;min-width:min(100%,260px)}
.phsearch input{width:100%;font:inherit;font-size:13px;padding:.42rem .55rem;border:1px solid var(--border);border-radius:8px;background:var(--panel);color:var(--ink)}
.phsearch input:focus-visible{outline:2px solid var(--accent);outline-offset:-1px}
.chips{display:flex;flex-wrap:wrap;gap:6px;margin:.55rem auto 0;max-width:520px}
.chips button,.miniBtn{appearance:none;border:1px solid var(--border);background:var(--panel);color:var(--sub);font:inherit;font-size:12px;padding:.34rem .58rem;border-radius:8px;cursor:pointer}
.chips button:hover,.miniBtn:hover{background:var(--panel2);color:var(--ink)}
.phdetail h3{margin:0 0 .15rem;font-size:17px}
.phdetail .subline{font-size:12.5px;color:var(--muted);margin:0 0 .5rem}
.phactions{display:flex;gap:6px;flex-wrap:wrap;margin:.7rem 0 0}
.compareList{display:grid;gap:7px;margin-top:.7rem}
.compareItem{display:grid;grid-template-columns:1fr auto;gap:8px;align-items:center;border-top:1px solid var(--border);padding-top:7px;font-size:12.5px}
.compareItem b{font-weight:600}.compareItem span{color:var(--muted);font-variant-numeric:tabular-nums}
.cityCompareCell{text-align:center}
.tblBtn{padding:.28rem .58rem;font-size:11.5px}
.tblBtn.on{background:var(--accent-bg);color:var(--accent);border-color:transparent}
.cmpTop{display:flex;justify-content:space-between;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:.85rem}
.cmpTop b{color:var(--ink);font-size:14px}
.cmpTop span{font-size:12px;color:var(--muted)}
.cmpGrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
.cmpCard{background:var(--panel2);border:1px solid var(--border);border-radius:14px;padding:.9rem}
.cmpHead{display:flex;justify-content:space-between;gap:10px;align-items:flex-start;margin-bottom:.5rem}
.cmpHead h3{margin:0;font-size:15px;line-height:1.25}
.cmpMeta{font-size:12px;color:var(--muted);margin:.15rem 0 0}
.cmpBadge{display:inline-block;padding:2px 8px;border-radius:999px;background:var(--panel);border:1px solid var(--border);font-size:11px;color:var(--sub);white-space:nowrap}
.cmpActions{display:flex;justify-content:space-between;align-items:center;gap:10px;margin-top:.65rem}
.cmpActions .note{margin:0}
.cmpEmpty{margin:0}
.miniShead{display:flex;align-items:center;gap:10px;margin:1rem 0 0}
.miniShead h3{margin:0;font-size:17px;line-height:1.2}

/* ---- Public SEO guide pages ----------------------------------------------- */
/* The sans-serif stack is declared on .wrap, and .seoHero sits OUTSIDE it — so every
   SEO page rendered its h1/lede in the browser's default serif (Times New Roman at
   46px) directly above a sans-serif table. Nothing flagged it: the markup, the data
   and the mobile checks were all correct, it just looked unstyled. .hero (homepage)
   and .rsApp (/research/) each carry their own stack, which is why only the ~130
   pSEO pages were affected. Keep this in step with :root/.wrap. */
.seoHero{position:relative;isolation:isolate;min-height:clamp(260px,36vh,360px);display:flex;align-items:end;
 font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;line-height:1.6;
 background:var(--mid) center/cover no-repeat;background-image:var(--seo-hero);border-bottom:1px solid var(--border)}
.seoHero:before{content:"";position:absolute;inset:0;z-index:-1;background:linear-gradient(90deg,rgba(8,13,11,.72),rgba(8,13,11,.34) 58%,rgba(8,13,11,.18))}
/* Hero as a real <img>, not background-image: the preload scanner can only see the
   former, and this is the LCP element on every guide page. Absolutely positioned, so
   it sits under .seoHeroInner and contributes no layout shift. */
.seoHeroImg{position:absolute;inset:0;z-index:-2;width:100%;height:100%;object-fit:cover;display:block}
.seoHeroInner{width:100%;max-width:1000px;margin:0 auto;padding:2.1rem 1.25rem;color:#fff}
.seoHero .eyebrow,.seoHero .backlink,.seoHero .lede{color:#fff}
.seoHero .lede{opacity:.9}
.seoHero h1{font-size:clamp(32px,4vw,46px);max-width:18ch}
.seoPhotoCredit{max-width:1000px;margin:.45rem auto 0;padding:0 1.25rem;font-size:11.5px;color:var(--muted);
 font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif}
.seoGuide{padding-top:1.25rem}
.seoStats{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:10px;margin:0 0 1.4rem}
.seoStat{border:1px solid var(--border);background:var(--panel);border-radius:8px;padding:.85rem .9rem}
.seoStat span{display:block;font-size:11.5px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}
.seoStat b{display:block;margin:.25rem 0 .1rem;font-size:18px;line-height:1.2;color:var(--ink);font-variant-numeric:tabular-nums}
.seoStat em{display:block;font-style:normal;font-size:12.5px;color:var(--sub);line-height:1.35}
.seoSection{margin-top:1.35rem;padding-top:1.35rem;border-top:1px solid var(--border)}
/* Running prose. Only the explainer page uses it — every other SEO page is a table
   plus a caption, and that is deliberate (SEO.md: no prose per city). */
.seoProse p{font-size:15.5px;line-height:1.65;color:var(--sub);max-width:68ch;margin:0 0 1rem}
.seoProse p:last-child{margin-bottom:0}
.seoProse em{font-style:normal;color:var(--ink);font-weight:600}
.seoTableWrap{overflow-x:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--border);border-radius:8px;background:var(--panel)}
.seoTable{width:100%;min-width:860px;border-collapse:collapse;font-size:14.5px;font-variant-numeric:tabular-nums}
.seoTable th,.seoTable td{text-align:right;padding:.62rem .7rem;border-bottom:1px solid var(--border);white-space:nowrap}
.seoTable th:first-child,.seoTable td:first-child{text-align:left}
/* Sticky header: these tables run to 100+ rows, and a column heading that scrolls
   away turns the rest into unlabelled numbers. The wrapper scrolls on X, the page
   on Y, so `position:sticky` here sticks to the VIEWPORT — which is what we want. */
/* Sentence case, not caps: a guide page stacks 58 header+body rows across 6 tables,
   and all-caps at that volume is measurably slower to read. */
.seoTable thead th{position:sticky;top:0;z-index:1;font-size:13px;color:var(--muted);text-transform:none;letter-spacing:0;font-weight:600;background:var(--panel2)}
/* Row banding + hover. A 100-row grid with no banding is where the eye loses its
   place mid-row; this is the cheapest readability win on the whole SEO surface. */
.seoTable tbody tr:nth-child(even){background:color-mix(in srgb,var(--ink) 3.5%,transparent)}
.seoTable tbody tr:hover{background:color-mix(in srgb,var(--accent) 11%,transparent)}
/* Value tint: same green->red ramp as the deep-dive map and ratioScale() in
   common.js, applied to the ratio + cost columns so a long table is scannable
   without reading a single number. The background AND the per-cell ink are emitted
   inline by make_seo_pages.py — no single text colour clears WCAG AA across a
   green->red ramp, so tint_ink() picks it from the background's luminance. Do NOT
   add a `color` here: it would override that and re-break one end of the ramp. */
.seoTable td.tint{font-weight:600}
/* The global `th` rule is 11.5px uppercase (built for the dense app tables). Row
   labels here are content — "Rent, 1-bed outside centre" — so they reset to body size. */
.seoTable tbody th{color:var(--ink);font-weight:600;font-size:14.5px;text-transform:none;letter-spacing:0}
.seoTable tbody tr:last-child th,.seoTable tbody tr:last-child td{border-bottom:0}
.seoSource{margin:.65rem 0 0;font-size:12.5px;color:var(--muted)}
.seoTableSm{min-width:0}
.seoTable small{color:var(--muted);font-weight:400;font-size:11px}
a.seoStat{display:block;text-decoration:none;transition:border-color .12s,transform .12s}
a.seoStat:hover{border-color:var(--accent)}
.rankChart{display:flex;flex-direction:column;gap:7px}
.rankBar{display:grid;grid-template-columns:130px 1fr 42px;gap:10px;align-items:center;font-size:13px}
.rankBar .rbCity{color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rankBar .rbTrack{background:var(--panel2);border-radius:5px;height:16px;overflow:hidden}
.rankBar .rbFill{display:block;height:100%;background:var(--accent);border-radius:5px}
.rankBar .rbVal{color:var(--muted);text-align:right;font-variant-numeric:tabular-nums}
@media (max-width:640px){.rankBar{grid-template-columns:92px 1fr 38px;font-size:12px}}
.seoSplit{display:grid;grid-template-columns:minmax(0,1fr) minmax(260px,.62fr);gap:18px;align-items:start}
.seoSplit p{color:var(--sub);margin:.25rem 0 .7rem}
/* Homepage data callout (#uaCallout). Grid so the numbers sit beside the copy on
   desktop and stack under it on a phone — see the 760px rule below. */
#uaCallout{margin-top:1.6rem}
.uaCard{display:grid;grid-template-columns:1.35fr .9fr auto;gap:1rem 1.4rem;align-items:center;
  border:1px solid var(--border);border-left:4px solid var(--accent);background:var(--panel);
  border-radius:10px;padding:1.05rem 1.15rem}
.uaCopy h2{margin:.15rem 0 .3rem;font-size:clamp(19px,2.1vw,24px);line-height:1.2}
.uaCopy p:last-child{margin:0;color:var(--sub);font-size:14px}
.uaStats{display:flex;gap:1.25rem;flex-wrap:wrap}
.uaStats span{display:flex;flex-direction:column;font-size:11.5px;color:var(--muted);line-height:1.3}
.uaStats b{font-size:20px;color:var(--ink);font-variant-numeric:tabular-nums;line-height:1.15}
.uaCard .btnPrimary{white-space:nowrap}
@media (max-width:760px){
 .uaCard{grid-template-columns:1fr;gap:.85rem}
 .uaStats{gap:1rem}
 .uaCard .btnPrimary{justify-self:stretch;text-align:center}
}
/* --- /ukraine-refugees/ presentation ------------------------------------------ */
/* EU adult sex split. Four number tiles cannot convey a proportion — the reader would
   have to divide 1.9M by 1.15M in their head — so the headline skew gets one bar. */
.uaSplit{margin:.9rem 0 0;padding:.85rem .95rem;border:1px solid var(--border);
  border-radius:10px;background:var(--panel)}
.uaSplitHead{display:flex;justify-content:space-between;align-items:baseline;gap:1rem;
  font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}
.uaSplitHead b{font-size:14px;color:var(--ink);text-transform:none;letter-spacing:0;
  font-variant-numeric:tabular-nums}
.uaSplitBar{display:flex;height:16px;margin:.5rem 0 .4rem;border-radius:999px;overflow:hidden}
.uaSplitF{background:var(--warm,#c60)}
.uaSplitM{flex:1;background:#2f5f96}
.uaSplitKey{display:flex;justify-content:space-between;font-size:12.5px;color:var(--sub);
  font-variant-numeric:tabular-nums}
.uaSplitKey span{display:flex;align-items:center;gap:.35rem}
.uaDotF,.uaDotM{width:9px;height:9px;border-radius:50%;display:inline-block}
.uaDotF{background:var(--warm,#c60)}
.uaDotM{background:#2f5f96}
/* Map + leaderboard side by side: the map answers "where", the list answers "which",
   and putting them in one row means neither needs a scroll to compare against. */
.uaMapRow{display:grid;grid-template-columns:minmax(0,1fr) 210px;gap:1rem;align-items:start}
.uaLead{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}
.uaLead li{display:grid;grid-template-columns:1.2rem 1fr auto;grid-template-areas:"n c v" "n c u";
  align-items:center;gap:0 .5rem;padding:.45rem .6rem;border:1px solid var(--border);
  border-radius:8px;background:var(--panel);font-size:13px}
.uaLeadN{grid-area:n;color:var(--muted);font-variant-numeric:tabular-nums;font-size:11.5px}
.uaLeadC{grid-area:c;color:var(--ink);font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis}
.uaLead b{grid-area:v;color:var(--accent);font-size:15px;font-variant-numeric:tabular-nums;text-align:right}
.uaLead em{grid-area:u;font-style:normal;font-size:10.5px;color:var(--muted);text-align:right}
/* Map labels. Halo via paint-order so a name stays legible over a dark fill without a
   background rect that would hide the geometry it sits on. */
.uaMapLbl{font-size:11px;font-weight:700;fill:#10231c;stroke:#fff;stroke-width:2.6px;
  paint-order:stroke fill;pointer-events:none}
.uaMapVal{font-weight:800;fill:#0b5f47}
/* Caveat cards. These are what keep the page honest, so they must be read — three
   stacked paragraphs at the foot of a data page is exactly where a reader stops. */
.uaNotes{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:.8rem}
.uaNote{border:1px solid var(--border);border-top:3px solid var(--accent);border-radius:8px;
  padding:.8rem .9rem;background:var(--panel)}
.uaNote h3{margin:0 0 .35rem;font-size:14px;line-height:1.25}
.uaNote p{margin:0;font-size:13px;color:var(--sub);line-height:1.5}
/* The Poland card runs to two paragraphs — it is the one caveat a reader has to follow
   rather than skim, so it gets the space and spans the grid where there is room. */
.uaNote p+p{margin-top:.5rem}
.uaNote b{color:var(--ink)}
/* In-cell bars. Six columns of raw digits force the reader to compare by reading; a bar
   behind the number turns each column into a shape. Behind, not beside: a bar column of
   its own would double the table width for no extra information. */
.seoTable td.hasBar{position:relative}
.cellBar{position:absolute;left:0;bottom:0;height:2px;background:var(--accent);opacity:.3}
.cellBar.strong{height:3px;opacity:.55}
/* Trend: arrow AND sign, never colour alone — growing vs draining is the point of the
   column, and red/green with no second cue fails for a colour-blind reader. */
.seoTable td.trend{font-variant-numeric:tabular-nums}
.trArrow{margin-right:.25rem;font-size:9px}
.seoTable td.trend.up{color:var(--accent)}
.seoTable td.trend.down{color:var(--warm,#c60)}
.seoTable td.trend.flat{color:var(--muted)}
/* Ratio shift. Polarity is the SITE's, not the trend column's: the shared ramp reads
   green = more women, red = more men, so a NEGATIVE shift (toward women) is the green
   one. Opposite sign convention to .trend above, which is why it gets its own classes
   rather than reusing them — one of these two would always have been backwards. */
.seoTable td.shiftDown{color:var(--accent);font-variant-numeric:tabular-nums}
.seoTable td.shiftUp{color:var(--warm,#c60);font-variant-numeric:tabular-nums}
.seoTable td.shiftFlat{color:var(--muted);font-variant-numeric:tabular-nums}
@media (max-width:760px){
 .uaMapRow{grid-template-columns:1fr}
 .uaLead{flex-direction:row;flex-wrap:wrap}
 .uaLead li{flex:1 1 140px}
}
/* Europe choropleth on /ukraine-refugees/. Baked SVG, so it only needs sizing.
   The fills are LIGHT-THEME hex baked at generate time (a static page cannot ask the
   browser for a theme), so in dark mode the map sits on its own light card rather than
   glowing against a dark page — same call the hero's baked fallback fill makes. */
.uaMapWrap{border:1px solid var(--border);border-radius:10px;background:#f4f5f0;
  padding:.5rem;overflow:hidden}
.uaMap{display:block;width:100%;height:auto}
.uaMap path{vector-effect:non-scaling-stroke}
.uaMapLegend{display:flex;align-items:center;gap:.55rem;margin:.6rem 0 0;font-size:12px;
  color:var(--muted);font-variant-numeric:tabular-nums}
.uaLegRamp{display:flex;flex:0 1 220px;height:10px;border-radius:999px;overflow:hidden;
  border:1px solid var(--border)}
.uaLegRamp span{flex:1}
/* Collapsed rows. display:none rather than height/opacity so the sticky header's
   scroll behaviour and the zebra striping both recompute against the visible set. */
.seoTable tr.rowHidden{display:none}
.seoMoreBtn{display:block;width:100%;margin:.55rem 0 0;padding:.6rem .8rem;font:inherit;
  font-size:13.5px;font-weight:600;color:var(--accent);background:var(--panel);
  border:1px dashed var(--border);border-radius:8px;cursor:pointer}
.seoMoreBtn:hover{border-color:var(--accent);border-style:solid}
.seoMoreBtn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* Sortable headers. The th keeps its sticky background; the button is the focusable
   control inside it, sized to fill the cell so the whole header is the hit area. */
.seoTable th[data-sort]{padding:0}
.seoTable th[data-sort] button{display:flex;align-items:center;gap:.3rem;width:100%;
  padding:.62rem .7rem;background:none;border:0;font:inherit;color:inherit;
  font-weight:600;cursor:pointer;text-align:inherit}
.seoTable th[data-sort]:first-child button{justify-content:flex-start}
.seoTable th[data-sort]:not(:first-child) button{justify-content:flex-end}
.seoTable th[data-sort] button:hover{color:var(--accent)}
.seoTable th[data-sort] button:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
/* Arrow is CSS-only and driven by aria-sort, so the visual state cannot drift from the
   state screen readers are told. Neutral columns show a faint double caret on hover. */
.sortArrow{width:.7em;font-size:11px;line-height:1;opacity:.35}
.sortArrow:before{content:"\2195"}
.seoTable th[aria-sort] .sortArrow{opacity:1;color:var(--accent)}
.seoTable th[aria-sort="ascending"] .sortArrow:before{content:"\2191"}
.seoTable th[aria-sort="descending"] .sortArrow:before{content:"\2193"}
/* In-table upsell on /ukraine-refugees/: a deep-dive link beside the three countries
   that have one. Deliberately small — the free table has to read as a complete table
   first, and an equal-weight link on every other row would read as an ad. */
.seoRowPro{margin-left:.4rem;font-size:11.5px;font-weight:600;white-space:nowrap;
  color:var(--accent);text-decoration:none;border-bottom:1px dotted currentColor}
.seoRowPro:hover{border-bottom-style:solid}
.seoCta{border:1px solid var(--border);background:var(--panel2);border-radius:8px;padding:1rem}
.seoCta .btnPrimary{display:inline-flex;margin-top:.35rem}
/* Per-item price tables. auto-fit collapses 4 -> 2 -> 1 column with no breakpoint;
   each table keeps its own overflow-x via .seoTableWrap so the page never scrolls. */
.seoPriceGrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(258px,1fr));gap:14px}
.seoPriceCol h3{font-size:14px;margin:0 0 .45rem;color:var(--sub);font-weight:600}
.seoInlineLinks{display:flex;flex-wrap:wrap;gap:8px;margin-top:1.4rem}
.seoInlineLinks a{border:1px solid var(--border);background:var(--panel);border-radius:8px;padding:.42rem .7rem;color:var(--sub);text-decoration:none;font-size:13px}
.seoInlineLinks a:hover{color:var(--ink);background:var(--panel2)}
@media(max-width:720px){
 .seoSplit{grid-template-columns:1fr}
 .seoHeroInner{padding-top:1.7rem;padding-bottom:1.7rem}
}

/* Philippines context layers */
.religionBar{display:flex;height:18px;overflow:hidden;border-radius:7px;background:var(--mid);gap:2px}
/* The 2px surface gap is not decoration: it is the secondary encoding that makes the
   dark-mode palette legal (worst adjacent CVD ΔE 10.3 sits in the floor band, which
   requires separation beyond hue alone). Do not remove it to "tighten" the bar. */
.religionBar span{min-width:3px}
.religionList{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.45rem .9rem;margin-top:.8rem}
.religionRow{display:grid;grid-template-columns:10px 1fr auto;gap:.45rem;align-items:center;font-size:13px;color:var(--sub)}
.religionRow b{color:var(--ink);font-variant-numeric:tabular-nums}
.religionDot{width:9px;height:9px;border-radius:50%}
.langEng{display:flex;justify-content:space-between;align-items:center;gap:10px;margin:.85rem 0 0;padding-top:.75rem;border-top:1px solid var(--border);font-size:13.5px}
.langEng .k{color:var(--sub)}
.langEng .v{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
.pyrModelBar{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:.7rem}
.pyrModelLabel{font-size:12.5px;color:var(--muted)}
.pyrTop{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-bottom:.9rem}
.pyrStat{background:var(--panel2);border:1px solid var(--border);border-radius:12px;padding:.7rem .8rem}
.pyrStat b{display:block;font-size:20px;line-height:1.1;color:var(--ink);font-variant-numeric:tabular-nums}
.pyrStat span{display:block;margin-top:.2rem;font-size:12px;color:var(--muted)}
.pyrAxis{display:grid;grid-template-columns:56px 1fr 54px 1fr 56px 48px;gap:8px;align-items:end;margin:0 0 .35rem;font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}
.pyrAxis span:nth-child(1){grid-column:2;text-align:left}
.pyrAxis span:nth-child(2){grid-column:4;text-align:right}
.pyrAxis span:nth-child(3){grid-column:6;text-align:right}
.pyrRows{display:grid;gap:4px}
.pyrRow{display:grid;grid-template-columns:56px 1fr 54px 1fr 56px 48px;gap:8px;align-items:center}
.pyrVal{font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.pyrValL{text-align:right}
.pyrValR{text-align:left}
.pyrValRatio{text-align:right;color:var(--sub)}
.pyrValRatio.pyrRatioGood{color:#3b7dd8;font-weight:600}
.pyrValRatio.pyrRatioBad{color:var(--warm);font-weight:600}
.pyrAge{text-align:center;font-size:11.5px;color:var(--sub);font-variant-numeric:tabular-nums}
.pyrSide{height:15px;background:var(--panel2);border-radius:999px;overflow:hidden;border:1px solid var(--border);display:flex;align-items:stretch}
.pyrSideL{justify-content:flex-end}
.pyrSideR{justify-content:flex-start}
.pyrBar{display:block;height:100%}
.pyrBarL{background:#3f78c0}
.pyrBarR{background:#c0392b}
/* women's side: dark = matched to men 5 yrs older (suitor pool), pale = surplus */
.pyrPool{background:#8f1d28}
.pyrSurplus{background:#e79a93}
/* rows where the older-male cohort outnumbers the women: split into two stacked
   half-height lanes (dark = older-male count on top, light = women below) so the
   dark-red overhang is visible. Same 15px height as normal rows. */
.pyrSideR.pyrSplit{display:grid;grid-template-columns:minmax(0,1fr);grid-template-rows:1fr 1fr;gap:0;align-items:stretch;justify-items:stretch}
.pyrSideR.pyrSplit .pyrLane{display:block;width:100%;min-width:0;box-sizing:border-box;overflow:hidden}
.pyrSideR.pyrSplit .pyrOlderMale{display:block;height:100%;background:#8f1d28}
.pyrSideR.pyrSplit .pyrFemaleBase{display:block;height:100%;background:#e79a93}
/* divider above the first row where the older-male cohort outnumbers the women:
   marks where the dating-pool ratio turns unfavourable */
.pyrRow.pyrBadStart{position:relative}
.pyrRow.pyrBadStart::before{content:"";position:absolute;left:0;right:0;top:-3px;border-top:1.5px dashed var(--muted);pointer-events:none}
.pyrNote{margin:.85rem 0 0}
.fkey{display:inline-flex;align-items:center;gap:5px;margin-left:10px;white-space:nowrap}
.fkey i{width:14px;height:11px;border-radius:3px;display:inline-block}
.fkey i.fhatch{background:#6b6f66;opacity:.42}
#prelview[hidden]{display:none}
.relPick{display:inline-flex;align-items:center;gap:.45rem;font-size:12.5px;color:var(--sub)}
.relPick[hidden]{display:none}
.relPick select{font:inherit;font-size:12.5px;max-width:210px;padding:.36rem .5rem;border:1px solid var(--border);
 border-radius:9px;background:var(--panel);color:var(--ink);cursor:pointer}
.relPick select:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.wxCities{flex-wrap:wrap;max-width:100%}
.wxSum{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;font-size:13px;color:var(--sub);margin:.85rem 0 .7rem}
.wxSum b{color:var(--ink);font-variant-numeric:tabular-nums}
.wxLegend{display:inline-flex;align-items:center;gap:5px;margin-left:auto;font-size:11.5px;color:var(--muted)}
.wxLegend i{width:15px;height:11px;border-radius:3px;display:inline-block}
/* The month axis cannot shrink to 375px, so it scrolls inside this box
   instead of widening the page. Row labels stay pinned while it scrolls. */
.wxScroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.wxTable{border-collapse:separate;border-spacing:3px;min-width:660px;width:100%;table-layout:fixed}
.wxTable th{font-weight:600;font-size:11.5px;color:var(--muted);padding:.2rem .3rem;text-align:center}
.wxTable thead th.wxNow{color:var(--ink)}
/* table-layout:fixed takes column widths from the FIRST row, so the label
   column must be sized on the thead cell, not on the tbody th. */
.wxTable thead th:first-child{width:94px}
.wxTable th[scope="row"]{position:sticky;left:0;z-index:1;text-align:left;color:var(--sub);
 background:var(--panel);white-space:nowrap;cursor:help;padding-right:.5rem}
.wxCell{border-radius:7px;text-align:center;padding:.4rem .2rem;line-height:1.2}
.wxCell b{display:block;font-size:13px;color:var(--ink);font-variant-numeric:tabular-nums}
.wxCell span{display:block;font-size:10.5px;color:var(--sub)}
.wxCell.wxNow{box-shadow:inset 0 0 0 2px var(--ink)}
/* Crowds row when no monthly tourism series exists — a stated gap, not a dropped row. */
.wxCell.wxCellNone{background:var(--mid)}
.wxCell.wxCellNone b{color:var(--sub);font-weight:600}
.wxNa{text-align:center;color:var(--muted);background:var(--nodata);border-radius:7px}
.wxSource{margin:.8rem 0 0}

/* cross-page navigation */
.backlink{color:var(--accent);text-decoration:none;font-weight:600}
.backlink:hover{text-decoration:underline}
.deepLink{display:inline-block;margin-top:.8rem;color:var(--accent);text-decoration:none;font-weight:600;font-size:13.5px}
.deepLink:hover{text-decoration:underline}
.rowLink{color:var(--ink);text-decoration:none}
.rowLink:hover{color:var(--accent);text-decoration:underline}

/* country deep-dive cards */
/* ---------- city shortlist cards (browse mode) ---------- */
.cityViewRow{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:.8rem}
.citySortControl{display:flex;align-items:center;gap:.35rem;margin-left:auto}
.citySortLabel{display:flex;align-items:center;gap:.35rem;font-size:13px;color:var(--sub);font-weight:600}
.citySortLabel select{font:inherit;font-size:13px;color:var(--ink);background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:.42rem 1.8rem .42rem .6rem}
.citySortDir{appearance:none;border:1px solid var(--border);background:var(--panel);color:var(--ink);border-radius:8px;width:34px;height:34px;font:inherit;font-weight:800;cursor:pointer}
.citySortDir:hover{border-color:var(--accent);color:var(--accent)}
.cityCards{display:grid;grid-template-columns:repeat(auto-fill,minmax(215px,1fr));gap:12px;min-height:600px}
.cityCards[hidden]{display:none}
@media(min-width:1001px){
 .citiesFull{width:calc(100vw - var(--sbw,0px));margin-left:calc(50% - 50vw + var(--sbw,0px)/2);margin-right:calc(50% - 50vw + var(--sbw,0px)/2);padding-inline:2rem;box-sizing:border-box}
}
/* city filter bar (nomad-style, honest presets) */
.cityFilterBar{margin:0 0 .9rem}
.cityAgeRow{display:flex;gap:12px 18px;align-items:center;flex-wrap:wrap;margin:0 0 .9rem}
.cityFilterMain{display:flex;gap:.5rem;align-items:center;flex-wrap:wrap}
.cityFilterSearch{flex:1;min-width:180px;font:inherit;font-size:14px;padding:.5rem .7rem;border:1px solid var(--border);border-radius:10px;background:var(--bg);color:var(--ink)}
.cityFilterDropWrap{position:relative}
.cityFilterBtn{appearance:none;font:inherit;font-size:13px;font-weight:600;padding:.5rem .8rem;border:1px solid var(--border);border-radius:10px;background:var(--panel);color:var(--ink);cursor:pointer}
.cityFilterBtn.on{border-color:var(--accent);color:var(--accent)}
.cityFilterClear{appearance:none;font:inherit;font-size:13px;padding:.5rem .7rem;border:1px solid var(--border);border-radius:10px;background:transparent;color:var(--sub);cursor:pointer}
.cityFilterPop{position:absolute;top:100%;right:0;margin-top:6px;z-index:40;background:var(--panel);border:1px solid var(--border);border-radius:12px;box-shadow:0 12px 32px rgba(0,0,0,.22);padding:.7rem .8rem;min-width:300px;max-height:60vh;overflow:auto}
.cityFilterPop[hidden]{display:none}
.cityFilterPopScroll{display:grid;grid-template-columns:repeat(2,minmax(130px,1fr));gap:.1rem 1.2rem}
/* Sheet chrome is mobile-only: on desktop this is a dropdown anchored to its own
   button, which is already the visible owner and the close control. */
.cityFilterPopHead,.cityFilterPopFoot{display:none}
.cityFilterScrim{display:none}
.cityFilterGrpH{font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);margin:.35rem 0 .2rem;font-weight:700}
.cityChip{display:block;width:100%;text-align:left;appearance:none;font:inherit;font-size:13px;padding:.32rem .55rem;margin:.12rem 0;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--ink);cursor:pointer}
.cityChip.on{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600}
.cityFilterActive{display:flex;flex-wrap:wrap;gap:.35rem;margin-top:.55rem}
.cityChipSm{width:auto;font-size:12px;padding:.25rem .5rem;margin:0}
.cityMapWrap[hidden]{display:none}
.cityMapCtl{margin:0 0 .6rem;display:flex;gap:.5rem;align-items:center;flex-wrap:wrap}
.cityMapSeg{max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.cityMapSeg::-webkit-scrollbar{display:none}
.cityMapSeg button{flex:0 0 auto;white-space:nowrap}
.cityMapLegend{display:flex;gap:.7rem;flex-wrap:wrap;align-items:center;font-size:12px;color:var(--muted);margin:.5rem 0 0}
.cityArcH{font-size:9px;font-weight:600;fill:var(--accent);text-anchor:middle;paint-order:stroke;stroke:var(--panel);stroke-width:2.5px;stroke-linejoin:round}
.cityHomeLabel{font-size:10px;font-weight:700;fill:var(--accent);paint-order:stroke;stroke:var(--panel);stroke-width:3px;stroke-linejoin:round}
.cityPinScore{font-size:9.5px;font-weight:800;fill:#fff;pointer-events:none}
.cityPinName{font-size:8.5px;font-weight:700;fill:#fff;paint-order:stroke;stroke:rgba(0,0,0,.55);stroke-width:3px;stroke-linejoin:round;pointer-events:none}
.cityPin:hover .cityPinDot{stroke:var(--accent);stroke-width:2px}
.cityMapLayout{display:flex;gap:12px;align-items:flex-start}
.cityMapLayout .cityMapBox{flex:1 1 auto;min-width:0}
.cityMapSide{flex:0 0 220px;align-self:stretch;max-height:78vh;overflow:auto;border:1px solid var(--border);border-radius:12px;background:var(--panel);padding:.75rem .8rem}
.cityMapSideH{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--ink);margin-bottom:.6rem}
.cityMapSideGrp{margin-bottom:.65rem}
.cityMapSideGrpH{font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:700;margin:.35rem 0}
.cityMapSideChips{display:flex;flex-wrap:wrap;gap:.35rem}
.cityMapSide .cityChip{width:auto;display:inline-flex;margin:0;border-radius:999px;font-size:12.5px;padding:.3rem .55rem}
.cityMapSideClear{margin-top:.4rem;width:100%;justify-content:center}
@media (max-width:760px){.cityMapLayout{display:block}.cityMapSide{display:none}}
.cityMapBox{position:relative;border:1px solid var(--border);border-radius:12px;overflow:hidden;background:var(--panel)}
.cityMapTip{position:absolute;pointer-events:none;opacity:0;transform:translate(-50%,-125%);background:var(--panel);border:1px solid var(--border);border-radius:7px;padding:.3rem .5rem;font-size:12px;color:var(--ink);box-shadow:0 4px 14px rgba(0,0,0,.2);white-space:nowrap;transition:opacity .1s;z-index:2}
@media (max-width:640px){
 /* Phone: a real bottom sheet — scrim behind, sticky title with ✕, scrolling chip
    list, and a footer that both clears and dismisses. The list scrolls INSIDE the
    sheet (flex column + min-height:0), so the page behind never moves. */
 .cityFilterPop{position:fixed;left:0;right:0;bottom:0;top:auto;margin:0;border-radius:14px 14px 0 0;
  max-height:80vh;z-index:60;padding:0;overflow:hidden;display:flex;flex-direction:column}
 @supports(height:1dvh){.cityFilterPop{max-height:80dvh}}
 .cityFilterPopHead{display:flex;align-items:center;justify-content:space-between;gap:.5rem;
  flex:0 0 auto;padding:.7rem .55rem .55rem .9rem;border-bottom:1px solid var(--border)}
 .cityFilterPopHead b{font-size:15px}
 .cityFilterPopX{appearance:none;border:none;background:transparent;color:var(--sub);font-size:24px;
  line-height:1;cursor:pointer;width:40px;height:40px;border-radius:999px}
 .cityFilterPopX:active{background:var(--panel2);color:var(--ink)}
 .cityFilterPopScroll{flex:1 1 auto;min-height:0;overflow:auto;-webkit-overflow-scrolling:touch;
  padding:.5rem .9rem .8rem}
 /* 36px tap targets — the desktop chip is ~28px tall, too small for a thumb. */
 .cityFilterPop .cityChip{min-height:36px;display:flex;align-items:center;font-size:13.5px}
 .cityFilterPopFoot{display:flex;align-items:center;gap:.5rem;flex:0 0 auto;
  padding:.6rem .9rem;border-top:1px solid var(--border);background:var(--panel2);
  padding-bottom:calc(.6rem + env(safe-area-inset-bottom))} /* clear the iOS home indicator */
 .cityFilterPopFoot button{appearance:none;font:inherit;font-size:14px;font-weight:600;
  min-height:44px;border-radius:10px;cursor:pointer}
 .cityFilterPopClear{flex:0 0 auto;padding:0 1rem;border:1px solid var(--border);background:transparent;color:var(--sub)}
 .cityFilterPopClear:disabled{opacity:.45}
 .cityFilterPopDone{flex:1 1 auto;border:1px solid var(--accent);background:var(--accent);color:var(--panel)}
 .cityFilterScrim{display:block;position:fixed;inset:0;z-index:55;background:rgba(10,12,10,.45)}
 .cityFilterScrim[hidden]{display:none}
 .citySortControl{margin-left:0;width:100%}
 .citySortLabel{flex:1}
 .citySortLabel select{width:100%}
 .cityFilterSearch{font-size:16px}
 /* Two cards per row on phones. minmax(0,1fr) lets columns shrink below their
    content width so the page never scrolls sideways; padding + banner bleed are
    trimmed to match the narrower card. Selectors are .cityCard-prefixed so they
    outrank the base .cc* rules that appear later in the file (equal specificity
    would otherwise lose on source order). */
 /* Widen the cards: bleed the grid out through most of the enclosing .card padding
    (negative inline margin) so two cards fill nearly the whole phone width with only
    a thin gutter, without shrinking .card padding globally (which would cramp the
    map/table/other cards). */
 .cityCards{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;min-height:0;margin-inline:-.8rem}
 .cityCard{padding:.7rem .7rem}
 .cityCard .ccArt{width:calc(100% + 1.4rem);margin:-.7rem -.7rem .55rem;height:64px}
 .cityCard .ccHead h3{font-size:14.5px}
 .cityCard .ccHero b{font-size:25px}
 /* Two-per-row cards run ~171px. The ratio/pool labels drop the redundant age band
    (shown once in "Ages 20–34" above the grid), so label + value now sit on ONE row
    here just like desktop — shorter, tidier than the old label-over-value stack. */
 .cityCard .ccStat{gap:4px;font-size:11.5px;line-height:1.25}
 .cityCard .ccStat .v{overflow-wrap:break-word}
 /* Two-per-row cards are ~171px, so pill + button fits on one line for a SHORT visa
    label and wraps for a long one — which put neighbouring Compare buttons ~40px
    apart. Stack them in every card instead: identical footer height, and the button
    goes full width (a bigger tap target than the wrapped version it replaces). */
 .cityCard .ccFoot{flex-direction:column;align-items:stretch;row-gap:6px}
 .cityCard .ccFootBtns{width:100%}
 .cityCard .ccFootBtns>*{flex:1;justify-content:center;min-height:36px}
 /* Map view: break the box wider than the enclosing card, but leave a phone gutter
    so it does not run flush to the screen edge. */
 .cityMapBox{width:calc(100vw - 24px - var(--sbw,0px));margin-left:calc(50% - 50vw + 12px + var(--sbw,0px)/2);border-radius:12px;border-left:1px solid var(--border);border-right:1px solid var(--border)}
}
/* Column flex + margin-top:auto on the footer pins the visa pill / Compare button to
   the card's bottom edge. The grid already stretches every card in a row to the same
   height, but without this the footer floated up under whatever content the card
   happened to have, so neighbouring Compare buttons sat at different heights. */
.cityCard{display:flex;flex-direction:column;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:.85rem .95rem;cursor:pointer;min-width:0;overflow:hidden;transition:border-color .12s,transform .12s,box-shadow .12s}
/* full-bleed landmark banner: cancel the card padding on top + sides, keep
   the card's rounded top corners. slice-scaled so it fills the band. */
/* max-width:none overrides the global img,svg{max-width:100%}, which would
   otherwise clamp the banner back to content width and kill the full bleed. */
.ccArt{display:block;width:calc(100% + 1.9rem);max-width:none;height:72px;margin:-.85rem -.95rem .7rem;border-radius:11px 11px 0 0}
.ccPhoto{object-fit:cover;background:var(--panel2)}
.photoCredits{margin-top:.7rem;font-size:12px;color:var(--muted)}
.photoCredits summary{cursor:pointer;color:var(--sub)}
.photoCredits ul{margin:.5rem 0 0;padding-left:1.1rem;display:grid;gap:.25rem}
.photoCredits a{color:var(--accent);text-decoration:none}
.photoCredits a:hover{text-decoration:underline}
.cityCard:hover,.cityCard:focus-visible{border-color:var(--accent);transform:translateY(-2px);box-shadow:0 6px 20px rgba(0,0,0,.08);outline:none}
.cityCard.on{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
.ccHead{display:flex;justify-content:space-between;align-items:baseline;gap:8px}
.ccHead h3{margin:0;font-size:16px;letter-spacing:-.01em}
.ccRank{color:var(--muted);font-size:12px;font-variant-numeric:tabular-nums;white-space:nowrap}
.ccCountry{margin:.05rem 0 .45rem;color:var(--muted);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Card headline: one big number (Geomaxxing Score when unlocked, else Your Fit) plus
   a small qualifier line. flex-wrap + the 100% basis on .ccHeroSub push the
   qualifier onto its own row, so the two never compete for the same baseline. */
.ccHero{display:flex;align-items:baseline;gap:7px;margin-bottom:.55rem;flex-wrap:wrap}
.ccHero b{font-size:30px;font-weight:600;letter-spacing:-.02em;color:var(--accent);font-variant-numeric:tabular-nums;line-height:1}
.ccHero span{font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--muted)}
.ccHero .ccHeroSub{flex:0 0 100%;margin-top:.25rem;font-size:10.5px;letter-spacing:.04em;text-transform:none;color:var(--sub)}
.ccHero .ccHeroSub a{color:var(--accent);text-decoration:none}
.ccHero .ccHeroSub a:hover{text-decoration:underline}
/* Unlocked card whose city has no Geomaxxing Score: the slot still belongs to that
   score, so it prints a muted em dash rather than borrowing the fit number. */
.ccHero.ccHeroNone b{color:var(--muted)}
/* Your Fit as a mini Geomaxxing Score — accent + tabular figures like the headline,
   at half its size, so it reads as the same family but never competes for the slot.
   Both selectors must outrank the generic `.ccHero b` / `.ccHero span` rules above
   (30px, and uppercase muted respectively), hence the .ccHeroSub qualifier. */
.ccHero .ccHeroSub .ccFitMini{font-size:15px;font-weight:700;line-height:1;color:var(--accent);font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.ccHero .ccHeroSub .ccFitMiniK{font-size:10.5px;letter-spacing:.04em;text-transform:none;color:var(--sub)}
/* Pre-quiz hero: no number exists yet (SCORING.md #5 — a default-weight score shown
   to everyone would be a second universal ranking), so the CTA occupies the slot the
   big figure normally holds and keeps the card height stable. */
.ccHero .ccQuizCta{font:inherit;font-size:13px;font-weight:600;letter-spacing:-.01em;line-height:1;
 padding:.5rem .8rem;border-radius:8px;border:1px solid var(--accent);background:transparent;
 color:var(--accent);cursor:pointer;text-transform:none}
.ccHero .ccQuizCta:hover{background:var(--accent);color:var(--bg)}
.ccHero .ccQuizCta:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* Same CTA inline in the compare table cell / city-modal row, where it sits on one
   text line rather than in the hero slot. */
.cdQuizCta{font:inherit;font-size:11.5px;font-weight:600;padding:.2rem .5rem;border-radius:6px;
 border:1px solid var(--accent);background:transparent;color:var(--accent);cursor:pointer;white-space:nowrap}
.cdQuizCta:hover{background:var(--accent);color:var(--bg)}
.cdQuizCta:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* "provisional" — part of the model has no data for this city. Deliberately visible
   rather than a tooltip-only detail: a thin score that reads as firm is exactly the
   failure the coverage rule exists to prevent. */
.ccHero .ccHeroFlag{display:inline-block;margin-left:5px;padding:1px 6px;border-radius:20px;font-size:9px;letter-spacing:.06em;color:var(--warm);background:var(--panel2)}
/* minmax(0,1fr) caps the column to the card width; without it the grid column
   grows to the widest row (a long language value), pushing every row's value
   past the card edge where overflow:hidden clips the level pills. */
.ccStats{display:grid;grid-template-columns:minmax(0,1fr);gap:.28rem;margin-bottom:.6rem}
.ccStat{display:flex;justify-content:space-between;align-items:baseline;gap:8px;font-size:12.5px;cursor:help;min-width:0}
.ccStat .k{color:var(--sub);flex:0 0 auto}
/* value may wrap (e.g. "Tagalog / Filipino" + its level pill) instead of overflowing */
.ccStat .v{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums;text-align:right;min-width:0;overflow-wrap:anywhere}
/* keep short compound values on one line so the narrow 2-up card doesn't split them:
   "🔒 Sign in" (icon + link) and the "+13h ahead" time-zone token */
.ccStat .v a{white-space:nowrap}
.ccStat .v .vNoWrap,.ccStat .v .tzDiff{white-space:nowrap}
.ccStatEnglish .v{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ccStatEnglish .pill{vertical-align:baseline}
/* time-zone gap, color-coded by how hard it is to overlap: easy (0-3h) reads as
   the accent green, mid (4-7h) muted, hard (8h+) the warm/red tone. */
.tzDiff-easy{color:var(--accent)}
.tzDiff-mid{color:var(--sub)}
.tzDiff-hard{color:var(--warm)}
.ccFoot{display:flex;justify-content:space-between;align-items:center;gap:8px;border-top:1px solid var(--border);padding-top:.55rem;margin-top:auto}
.ccFootBtns{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.ccGo{color:var(--accent);text-decoration:none;font-weight:600;font-size:12.5px;white-space:nowrap}
.ccGo:hover{text-decoration:underline}
.ccCmpBtn{appearance:none;border:1px solid var(--border);background:var(--panel2);color:var(--sub);font:inherit;font-size:12px;font-weight:600;padding:.34rem .62rem;border-radius:8px;cursor:pointer;white-space:nowrap}
.ccCmpBtn:hover{background:var(--mid);color:var(--ink)}
.ccCmpBtn.on{background:var(--accent-bg);border-color:transparent;color:var(--accent)}
/* Partner offer row (offers.js). Deliberately quieter than every metric on the
   card: muted text, no accent colour, no fill — a commercial link must never
   out-rank the data it sits under. Tap targets stay >=36px on touch. */
.ccOffers{display:flex;align-items:center;flex-wrap:wrap;gap:6px;margin-top:.5rem;padding-top:.5rem;border-top:1px dashed var(--border)}
.ccOfferTag{font-size:10px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--muted);text-decoration:none;border:1px solid var(--border);border-radius:5px;padding:.15rem .3rem;white-space:nowrap}
.ccOfferTag:hover{color:var(--sub)}
.ccOffer{font-size:12px;font-weight:600;color:var(--sub);text-decoration:none;border:1px solid var(--border);background:var(--panel2);border-radius:8px;padding:.34rem .55rem;white-space:nowrap}
.ccOffer:hover{color:var(--ink);background:var(--mid)}
.cmOffers{margin-top:.9rem}
@media (max-width:640px){
 .ccOffer{padding:.5rem .65rem}
}
.pill.visa-3{background:var(--accent-bg);color:var(--accent)}
.pill.visa-2{background:var(--mid);color:var(--sub)}
.pill.visa-1{background:var(--mid);color:var(--warm)}
.cityCompareBox{margin-top:1rem}
.cityCmpTop{display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:.8rem}
.cityCmpTop b{color:var(--ink);font-size:14px}
.cityCmpTop span{font-size:12px;color:var(--muted)}
.cityCmpColPop{width:280px}
.cityCmpColHead{justify-content:space-between}
.cityCmpColActions{display:flex;gap:.35rem}
.cityCmpColActions .rsMini{font-size:10.5px;text-transform:none;letter-spacing:0;padding:.2rem .5rem;min-height:26px}
.cityCmpColSel{margin-bottom:0}
.cityCmpColItem{display:flex;align-items:center;gap:.45rem;padding:.25rem .2rem;border-radius:8px}
.cityCmpColItem.is-drop{background:var(--panel2)}
.cityCmpColItem.is-dragging{opacity:.5}
.cityCmpColLabel{display:flex;align-items:center;gap:.45rem;flex:1;min-width:0;cursor:pointer}
.cityCmpColLabel span{font-size:12.5px;color:var(--ink);line-height:1.35}
.cityCmpGrip{color:var(--muted);font-size:12px;cursor:grab;user-select:none}
.cityCmpTable{width:auto;border-collapse:separate;border-spacing:0;font-size:12.5px}
.cityCmpTable td,.cityCmpTable .cityCmpCityCol{max-width:220px}
.cityCmpTable th,.cityCmpTable td{padding:.55rem .65rem;border-bottom:1px solid var(--border);vertical-align:top}
/* The city-name header row must stay visible while reading down the metrics.
   `position:sticky` on the thead only works against the NEAREST SCROLL ANCESTOR,
   and this table needs an overflow-x container on mobile (page must never scroll
   sideways) — an overflow-x:auto box computes overflow-y to auto too, so it was
   already the sticky context, just one that never scrolled. Capping its height
   makes it scroll for real, so the header sticks. Short tables never reach the cap
   and behave exactly as before. */
/* No `overscroll-behavior:contain` — chaining must stay ON, or a mobile flick that
   hits the bottom of the table dead-stops instead of carrying on down the page. */
.cityCmpScroll{overflow:auto;max-height:calc(100vh - 140px)}
.cityCmpTable thead th{position:sticky;top:0;background:var(--panel);z-index:2;
 box-shadow:inset 0 -1px 0 var(--border)}
/* Metric names stay put when the cities scroll sideways; the corner cell is both
   sticky axes at once, so it needs to outrank each. */
.cityCmpTable .cityCmpMetric{position:sticky;left:0;background:var(--panel);z-index:1}
.cityCmpTable thead th.cityCmpMetric{z-index:3}
.cityCmpTable th:first-child,.cityCmpTable td:first-child{text-align:left}
.cityCmpTable td{text-align:left}
.cityCmpMetric{width:170px;color:var(--muted);font-size:11.5px;text-transform:uppercase;letter-spacing:.05em}
.cityCmpMetric[title]{cursor:help}
.cityCmpCityCol{cursor:grab}
.cityCmpCityCol.is-drop{background:var(--panel2)}
.cityCmpCityCol.is-dragging{opacity:.55}
.cityCmpHead{display:flex;justify-content:space-between;align-items:flex-start;gap:8px}
.cityCmpHead b{display:block;color:var(--ink);font-size:14px;line-height:1.2}
.cityCmpHead span{display:block;margin-top:.15rem;color:var(--muted);font-size:11.5px;font-weight:500}
.cityCmpRemove{appearance:none;border:1px solid var(--border);background:var(--panel2);color:var(--sub);font:inherit;font-size:11.5px;padding:.25rem .52rem;border-radius:7px;cursor:pointer}
.cityCmpRemove:hover{background:var(--mid);color:var(--ink)}
.cityCmpWrap{display:block;border-radius:10px;padding:.45rem .55rem;margin:-.15rem 0}
.cityCmpWrap[title]{cursor:help}
.cityCmpMain{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
.cityCmpSub{display:block;margin-top:.18rem;color:var(--muted);font-size:11.5px;line-height:1.45}
.cityCmpTable td.dim{color:var(--muted)}
@media (max-width:640px){
 /* Full-bleed on phones so metric column + two city columns fit without a
    horizontal scroll. Negative margins cancel the outer .card (1rem) + .wrap
    (.55rem) side padding to reach the screen edges. */
 .cityCompareBox{margin-left:calc(-1rem - .55rem);margin-right:calc(-1rem - .55rem);padding:.7rem .4rem;border-radius:0;border-left:0;border-right:0}
 .cityCmpScroll{max-height:calc(100vh - 110px)}
 .cityCmpTable{width:100%;font-size:12px}
 .cityCmpTable th,.cityCmpTable td{padding:.5rem .35rem}
 .cityCmpMetric{width:84px;font-size:10px;letter-spacing:.02em}
 .cityCmpTable td,.cityCmpTable .cityCmpCityCol{max-width:none;min-width:118px}
 .cityCmpHead{gap:5px}
 .cityCmpHead b{font-size:12.5px}
 .cityCmpRemove{font-size:10px;padding:.2rem .4rem}
 .cityCmpMain{font-size:12.5px}
 .cityCmpWrap{padding:.35rem .3rem;margin:-.1rem 0}
}

.countryGrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px}
.countryCard{position:relative;overflow:hidden;display:flex;flex-direction:column;background:var(--panel);border:1px solid var(--border);border-radius:14px;padding:1.1rem;text-decoration:none;color:var(--ink);transition:border-color .12s,transform .12s,box-shadow .12s}
/* decorative country silhouette (home.js draws it from world_topo.json) */
.countryCard .cc-outline{position:absolute;right:-14px;bottom:-14px;width:104px;height:104px;pointer-events:none;opacity:.13;transition:opacity .12s,transform .12s}
.countryCard .cc-outline path{fill:var(--accent);stroke:none}
a.countryCard:hover .cc-outline{opacity:.22;transform:translateY(-2px)}
.countryCard>*:not(.cc-outline){position:relative;z-index:1}
a.countryCard:hover{border-color:var(--accent);transform:translateY(-2px);box-shadow:0 6px 20px rgba(0,0,0,.08)}
.countryCard .cc-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem}
.countryCard .cc-flag{display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;width:2.2rem;height:2.2rem}
.countryCard .cc-flag img{display:block;width:2rem;height:1.5rem;object-fit:cover;border-radius:3px;box-shadow:0 0 0 1px rgba(0,0,0,.14)}
.countryCard .cc-flagCode{font-size:12px;font-weight:800;color:var(--muted);letter-spacing:.03em}
.cc-badge{font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;color:var(--accent);background:var(--accent-bg);padding:2px 9px;border-radius:20px}
.cc-badge-soon{color:var(--muted);background:var(--panel2)}
.cc-badge-listing{color:#b4530f;background:var(--panel2)}
.cc-badge-planned{color:var(--muted);background:var(--panel2)}
.countryCard h3{margin:0 0 .3rem;font-size:18px}
.countryCard p{margin:0 0 .9rem;font-size:13px;color:var(--sub);line-height:1.55;flex:1}
.countryCard .cc-go{font-size:13px;font-weight:600;color:var(--accent)}
.countryCard.cc-soon{opacity:.72;cursor:default}
.countryCard.cc-soon .cc-go{color:var(--muted)}
.countryCard.cc-more{border-style:dashed}
.sheadSplit,.pageHeadSplit{display:flex;justify-content:space-between;align-items:flex-end;gap:1rem;flex-wrap:wrap}
.textBtn{display:inline-flex;align-items:center;gap:.3rem;color:var(--accent);text-decoration:none;font-weight:700;font-size:13.5px;white-space:nowrap}
.textBtn:hover{text-decoration:underline}
.countriesPage{padding-top:2rem}
.pageHead{margin-bottom:1.2rem}
.pageHead h1{margin:.15rem 0 .35rem;font-size:clamp(34px,5vw,56px);letter-spacing:-.03em}
#ctyTitle span{display:inline-block;font-family:"Apple Color Emoji","Segoe UI Emoji","Noto Color Emoji",system-ui,sans-serif;line-height:1;white-space:nowrap}
.countryCatalogTool{padding:1rem}
.countryCatalogControls{display:flex;justify-content:space-between;align-items:center;gap:.75rem;flex-wrap:wrap;margin-bottom:.7rem}
.countrySearch{flex:1;min-width:240px;font:inherit;font-size:14px;padding:.58rem .75rem;border:1px solid var(--border);border-radius:10px;background:var(--bg);color:var(--ink)}
.countryCounts{display:flex;flex-wrap:wrap;gap:.45rem;margin:.1rem 0 .85rem;color:var(--sub);font-size:12.5px}
.countryCounts span{display:inline-flex;gap:.25rem;align-items:center;background:var(--panel2);border:1px solid var(--border);border-radius:999px;padding:.22rem .55rem}
.countryCatalogGrid{min-height:260px}
.countryCatalogCard{min-height:220px}
.countryMeta{display:flex;flex-wrap:wrap;gap:.35rem;margin:.15rem 0 .55rem}
.countryMeta span{display:inline-flex;background:var(--panel2);border:1px solid var(--border);border-radius:999px;padding:.16rem .5rem;font-size:11.5px;color:var(--sub)}
.countrySrc{font-size:11.5px!important;margin:.1rem 0 .75rem!important;color:var(--muted)!important;flex:0!important}

/* ---------- dating market (country level) + data-level tags ---------- */
/* Level tags exist so a figure can never silently change granularity: every
   ratio shows the level it was MEASURED at, not the level of its row. */
.pill.lvl-country{background:var(--mid);color:var(--muted)}
.pill.lvl-city{background:var(--accent-bg);color:var(--accent)}
.pill.lvl-regional{background:var(--accent-bg);color:var(--accent)}
.pill.lvl-metro{background:var(--mid);color:var(--sub)}
.pill.src,.pill.ok{background:var(--accent-bg);color:var(--accent)}
.pill.warn{background:var(--mid);color:var(--warm)}
.pill.air-international{background:var(--accent-bg);color:var(--accent)}
.pill.air-domestic{background:var(--mid);color:var(--muted)}
h2 .pill,h3 .pill{vertical-align:middle;margin-left:.45rem;text-transform:none;letter-spacing:0}
td .pill{margin-left:.35rem;cursor:help}
td.dim{color:var(--muted)}

.dgrid{display:grid;grid-template-columns:1fr 1fr;gap:1.4rem 1.6rem}
.dh{font-size:14px;font-weight:600;margin:0 0 .6rem;color:var(--ink)}
.dapps{display:flex;flex-wrap:wrap;gap:.4rem}
.dapp{display:inline-flex;align-items:center;gap:.3rem;background:var(--panel2);
 border:1px solid var(--border);border-radius:9px;padding:.3rem .5rem;font-size:13px}
.dbig{font-size:26px;font-weight:600;margin:.1rem 0 .4rem;font-variant-numeric:tabular-nums;
 letter-spacing:-.02em;color:var(--accent)}
.drank{color:var(--muted);font-variant-numeric:tabular-nums;font-size:12px}
/* Ranked-column view of the Android usage rank. Per-cell alignment overrides
   the global right-aligned th,td. */
.appRank{width:100%;border-collapse:collapse;font-size:13px}
.appRank th{font-size:11px;text-transform:uppercase;letter-spacing:.05em;font-weight:500;color:var(--muted);padding:.3rem .45rem;border-bottom:1px solid var(--border)}
.appRank td{padding:.42rem .45rem;border-bottom:1px solid var(--border)}
.appRank tr:last-child td{border-bottom:0}
.appRank .arRank{width:32px;text-align:right;color:var(--muted);font-variant-numeric:tabular-nums}
.appRank .arName{text-align:left;font-weight:600;color:var(--ink)}
.appRank .arType{text-align:right;white-space:nowrap}

/* intent-mix colours double as the app-class key, so a chip and its bar segment
   always agree */
.cls-casual,.pill.cls-casual{background:#c0392b26;color:#b0392b}
.cls-relationship,.pill.cls-relationship{background:#0f6e5626;color:var(--accent)}
.cls-international,.pill.cls-international{background:#b4530f26;color:var(--warm)}
.cls-intl_local{background:#8a5cd626;color:#7a4fc4}
.cls-lgbtq,.pill.cls-lgbtq{background:#2b6cb026;color:#2b6cb0}
.cls-local{background:var(--mid);color:var(--sub)}
@media (prefers-color-scheme:dark){
 .cls-casual,.pill.cls-casual{color:#e2705f}
 .cls-lgbtq,.pill.cls-lgbtq{color:#6ba8e0}
 .cls-intl_local{color:#a98ae4}
}
@media (max-width:760px){.dgrid{grid-template-columns:1fr;gap:1.5rem}}

/* ---------- visa & length of stay ---------- */
.visaHead{margin:0 0 .8rem;padding:.55rem .8rem;border-left:3px solid var(--accent);background:var(--accent-bg);border-radius:0 7px 7px 0;font-size:14px;color:var(--ink)}
.visaTiers{margin-bottom:.4rem}
.visaPassSel{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:13px;color:var(--sub);margin:.2rem 0 0;min-width:0}
.visaPassSel select{font:inherit;font-size:13px;padding:.4rem .5rem;border:1px solid var(--border);border-radius:8px;background:var(--panel);color:var(--ink);max-width:100%;min-width:0}
.visaPassSel select:focus-visible{outline:2px solid var(--accent);outline-offset:-1px}
.visaUsd{color:var(--muted);font-weight:400}
.visaStats{display:flex;flex-wrap:wrap;gap:.6rem;margin:.2rem 0 1rem}
.visaStat{flex:1 1 150px;background:var(--panel2);border:1px solid var(--border);border-radius:10px;padding:.7rem .8rem}
.visaStatNum{display:block;font-size:22px;font-weight:700;font-variant-numeric:tabular-nums;color:var(--ink);line-height:1.1}
.visaStatLab{display:block;font-size:11.5px;color:var(--muted);margin-top:.25rem}
.visaStatGood{background:var(--accent-bg);border-color:transparent}
.visaStatGood .visaStatNum{color:var(--accent)}
.visaLadder{border-collapse:collapse;width:100%;min-width:520px;font-size:13px}
.visaLadder th{text-align:left;padding:.4rem .6rem;border-bottom:1px solid var(--border)}
.visaLadder td{padding:.55rem .6rem;border-bottom:1px solid var(--border);vertical-align:top;text-align:left}
.visaLadder .visaNum{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap;color:var(--sub)}
.visaNote{display:block;font-size:11.5px;color:var(--muted);margin-top:.15rem;max-width:44ch;white-space:normal}
.visaSkip{opacity:.45}.visaSkip b{text-decoration:line-through}
.visaBlock{padding:.8rem .9rem;border-radius:9px;background:var(--panel2);border:1px solid var(--border);font-size:13.5px;line-height:1.5}
.visaBlockWarn{border-left:3px solid var(--warm)}
.visaBlockGood{border-left:3px solid var(--accent)}
.visaExtras{display:grid;grid-template-columns:1fr 1fr;gap:.55rem;margin:.9rem 0 0}
.visaExtras>div{background:var(--panel2);border-radius:8px;padding:.55rem .7rem;font-size:12.5px;color:var(--sub);line-height:1.45}
.visaSteps{margin:.8rem 0 0}
.visaSteps summary{cursor:pointer;color:var(--accent);font-size:13px;font-weight:600}
.visaSteps ol{margin:.5rem 0 0;padding-left:1.2rem;color:var(--sub);font-size:13px;line-height:1.6}
.visaSrc a{color:var(--accent)}

/* ---------- can you live here ---------- */
.liveNet{border:1px solid var(--border);border-radius:11px;padding:.8rem .9rem;margin:0 0 1rem}
.liveNetHead{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;font-size:15px}
.liveWord{color:var(--sub);font-size:12.5px}
.liveNetNums{display:flex;flex-wrap:wrap;gap:.6rem 1.6rem;margin-top:.5rem;font-size:15px;font-variant-numeric:tabular-nums}
.liveNetNums i{color:var(--muted);font-size:11.5px;font-style:normal;font-variant-numeric:normal}
.liveTable{border-collapse:collapse;width:100%;font-size:13.5px}
.liveTable th,.liveTable td{text-align:center;padding:.5rem .5rem;border-bottom:1px solid var(--border);vertical-align:middle}
.liveTable thead th{color:var(--muted);font-weight:500;font-size:11.5px;text-transform:uppercase;letter-spacing:.04em}
.liveTable th[scope="row"]{text-align:left;font-weight:600;color:var(--ink);font-size:13.5px;text-transform:none;letter-spacing:0}
.liveScale{display:block;font-size:10px;color:var(--muted);text-transform:none;letter-spacing:0;font-weight:400;margin-top:1px}
.liveTable td b{display:block;font-size:16px;font-variant-numeric:tabular-nums;color:var(--ink)}
.liveTable td span{display:block;font-size:11px;color:var(--sub);margin-top:1px}
.liveNa{color:var(--muted)}
.livePm{margin:.8rem 0 0;background:var(--panel2);border-radius:9px;padding:.6rem .7rem}
.liveExtras{display:grid;grid-template-columns:1fr 1fr;gap:.55rem;margin:.9rem 0 0}
.liveExtras>div{background:var(--panel2);border-radius:8px;padding:.55rem .7rem;font-size:12.5px;color:var(--sub);line-height:1.45}

/* ---------- settle / long-stay visas ---------- */
.settleWrap{margin-top:1.1rem;padding-top:.9rem;border-top:1px solid var(--border)}
.settleH{font-size:16px;font-weight:600;margin:0 0 .1rem}
.settleSummary{cursor:pointer;color:var(--ink)}
.settleBody{margin-top:.6rem}
.settleCard{background:var(--panel2);border:1px solid var(--border);border-radius:10px;padding:.7rem .8rem;margin-bottom:.6rem}
.settleTop{display:flex;align-items:center;gap:.5rem;font-size:14.5px}
.settleTag{font-size:10.5px;font-weight:600;padding:1px 7px;border-radius:20px;text-transform:uppercase;letter-spacing:.03em}
.settleTag-settle{background:var(--accent-bg);color:var(--accent)}
.settleTag-new{background:var(--mid);color:var(--warm)}
.settleGrid{display:grid;grid-template-columns:repeat(3,1fr);gap:.5rem;margin:.55rem 0 .1rem;font-size:13px}
.settleGrid>div{color:var(--ink)}
.settleGrid span{display:block;font-size:10.5px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin-bottom:1px}
.settleCatch{margin:.5rem 0 0}

/* ---------- openness to foreigners ---------- */
.dopen{background:var(--panel2);border:1px solid var(--border);border-radius:11px;padding:.75rem .85rem;margin-bottom:1rem}
.dopenHead{display:flex;align-items:center;gap:.5rem;font-size:15px}
.dopenTag{font-size:11px;font-weight:600;padding:1px 8px;border-radius:20px;text-transform:uppercase;letter-spacing:.03em}
.dopenTag-high{background:var(--accent-bg);color:var(--accent)}
.dopenTag-moderate{background:var(--mid);color:var(--warm)}
.dopenTag-low,.dopenTag-verylow{background:var(--mid);color:var(--muted)}
.dopenBar{display:flex;height:14px;margin-top:.55rem;border-radius:7px;overflow:hidden;background:var(--mid)}
.dopenSeg{min-width:2px}
.dopenLoc{background:#8a5cd6}
.dopenIntl{background:var(--warm)}
.dopenRest{background:var(--mid)}

/* ---------- full ADM3 ratio table ---------- */
.a3Table{border-collapse:separate;border-spacing:0;font-size:12.5px;min-width:720px}
.a3pop{color:var(--sub);font-weight:600}
.a3Table th,.a3Table td{border-bottom:1px solid var(--border);padding:.4rem .5rem;text-align:center;font-variant-numeric:tabular-nums;white-space:nowrap}
.a3Table thead th{color:var(--muted);font-weight:500;font-size:11px;text-transform:uppercase;letter-spacing:.03em;cursor:pointer;background:var(--panel);user-select:none}
.a3Table thead th:hover,.a3Table thead th.sortOn{color:var(--accent)}
.a3Table thead th.sortOn:after{content:"";display:inline-block;margin-left:4px;border-left:3.5px solid transparent;border-right:3.5px solid transparent;vertical-align:middle}
.a3Table thead th.sortOn[data-dir="asc"]:after{border-bottom:5px solid currentColor}
.a3Table thead th.sortOn[data-dir="desc"]:after{border-top:5px solid currentColor}
.a3name{position:sticky;left:0;z-index:1;background:var(--panel);text-align:left!important;min-width:180px;max-width:180px;overflow:hidden;text-overflow:ellipsis}
.a3Table thead th.a3name{z-index:2}
.a3Table tbody th.a3name{font-weight:500;color:var(--ink);font-size:12.5px}
.a3na{color:var(--muted)}
.a3thin{opacity:.4}
/* Sample-margin badge beside a subregion name (ACS 5-year relative MOE on the sex
   ratio). Two tiers: >=10% muted, >=20% warm — the second is where the confidence
   interval is wide enough that the ratio should not be read as a real difference. */
.a3moe{margin-left:.35rem;font-size:9.5px;font-weight:600;color:var(--muted);white-space:nowrap;vertical-align:.1em}
.a3moe.wide{color:var(--warm)}
.a3Pager{display:flex;align-items:center;justify-content:center;gap:6px;flex-wrap:wrap;margin:.8rem 0 .15rem}
.a3Pager button{appearance:none;border:1px solid var(--border);background:var(--panel);color:var(--sub);font:inherit;font-size:12px;line-height:1;padding:.44rem .62rem;border-radius:8px;cursor:pointer;min-width:34px}
.a3Pager button:hover{background:var(--panel2);color:var(--ink)}
.a3Pager button.on{background:var(--accent-bg);border-color:var(--accent);color:var(--accent);font-weight:700}
.a3Pager button:disabled{opacity:.45;cursor:not-allowed}
.a3PagerGap,.a3PagerMeta{color:var(--muted);font-size:12px}
.a3PagerMeta{margin-left:4px}
.rankRegionPick{display:flex;flex-direction:column;gap:3px;min-width:min(100%,220px);font-size:11px;color:var(--sub);font-weight:600}
.rankRegionPick span{text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
.rankRegionPick select{width:100%;font:inherit;font-size:13px;color:var(--ink);background:var(--panel);border:1px solid var(--border);border-radius:8px;padding:.42rem 2rem .42rem .6rem}
.rankRegionPick select:focus-visible{outline:2px solid var(--accent);outline-offset:-1px}

/* ---------- disaster / singlehood / gender-norms blocks ---------- */
.riskHead{display:flex;align-items:baseline;gap:.55rem;flex-wrap:wrap}
.statBig{font-size:26px;font-weight:600;font-variant-numeric:tabular-nums}
.statBig small{font-size:14px;color:var(--muted);font-weight:500}
.riskWord{font-size:13px;color:var(--sub)}
.hazList{display:flex;flex-direction:column;gap:.5rem;margin:.7rem 0 0}
.hazRow{display:grid;grid-template-columns:118px 1fr 34px;gap:10px;align-items:center;font-size:13px}
.hazLbl{color:var(--ink)}
.hazTrack{height:9px;border-radius:6px;background:var(--mid);overflow:hidden}
.hazFill{display:block;height:100%;border-radius:6px}
.hazNum{text-align:right;font-variant-numeric:tabular-nums;font-weight:600}
.gnBar{display:flex;height:14px;margin:.2rem 0 .4rem;border-radius:7px;overflow:hidden;background:var(--mid)}
.gnSeg{min-width:2px}
.gnAgree{background:var(--warm)}
.gnMid{background:var(--muted)}
.gnDis{background:var(--accent)}
.gnKey{display:flex;flex-wrap:wrap;gap:.4rem 1rem;font-size:12px;color:var(--sub)}
.gnKey i{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:5px;vertical-align:-1px}
.gnKey i.gnAgree{background:var(--warm)}.gnKey i.gnMid{background:var(--muted)}.gnKey i.gnDis{background:var(--accent)}

/* ---------- section tabs (desktop) / accordion (mobile) ---------- */
/* One active section at a time. Desktop = a tab bar above a single panel;
   mobile = a stacked accordion (same single-open state). Default: City shortlist. */
/* The bar WRAPS rather than scrolling sideways: past ~10 tabs it no longer fits the
   1000px .wrap, and a horizontally-scrolled tab is a section nobody finds (a hidden
   scrollbar gives a mouse user no hint it's even there). Wrapping keeps every section
   one click away. row-gap leaves room for the active tab's underline on the top row. */
.secTabsWrap{margin:1.5rem 0 0;border-bottom:1px solid var(--border)}
.secTabs{display:flex;flex-wrap:wrap;column-gap:2px;row-gap:2px}
.secTab{appearance:none;border:0;background:transparent;color:var(--sub);font:inherit;font-size:14px;font-weight:600;padding:.62rem .9rem;cursor:pointer;white-space:nowrap;border-bottom:2px solid transparent;margin-bottom:-1px}
.secTab:hover{color:var(--ink)}
.secTab.is-active{color:var(--accent);border-bottom-color:var(--accent)}
.secTab:focus-visible{outline:2px solid var(--accent);outline-offset:-2px;border-radius:6px}
.secAccHead{display:none}
.secChev{color:var(--muted);font-size:12px;transition:transform .15s}
.secPanel{margin-top:0;padding-top:1.7rem;border-top:0;display:none}
.secPanel.is-active{display:block}
.secPanelBody{display:block}

/* ---------- common scams ---------- */
.scamLead{margin:0 0 .8rem}
.scamCard{background:var(--panel2);border:1px solid var(--border);border-left:3px solid var(--border);border-radius:10px;padding:.7rem .85rem;margin-bottom:.7rem}
.scamCard.scamSev-high{border-left-color:var(--warm)}
.scamCard.scamSev-medium{border-left-color:var(--mid)}
.scamTop{display:flex;align-items:center;flex-wrap:wrap;gap:.45rem;font-size:15px}
.scamSev{font-size:10.5px;font-weight:600;padding:1px 8px;border-radius:20px;text-transform:uppercase;letter-spacing:.03em;margin-left:auto}
.scamSevTag-high{background:var(--accent-bg);color:var(--warm)}
.scamSevTag-medium{background:var(--mid);color:var(--sub)}
.scamSevTag-low{background:var(--mid);color:var(--muted)}
.scamWho{margin:.4rem 0 .1rem;font-size:12.5px;color:var(--sub)}
.scamGrid{display:grid;grid-template-columns:1fr 1fr;gap:.6rem;margin:.55rem 0 .1rem;font-size:13px;line-height:1.5}
.scamGrid>div{color:var(--ink)}
.scamGrid span{display:block;font-size:10.5px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin-bottom:2px}
.scamSrc{margin:.55rem 0 0}

/* ---------- mobile / touch ---------- */
img,svg{max-width:100%}
@media (max-width:640px){
 .dapp{font-size:12.5px}
 .dbig{font-size:22px}
 h2 .pill,h3 .pill{display:inline-block;margin:.2rem 0 0 .4rem}
 .sheadTop{align-items:flex-start}
 /* tabs collapse to a stacked accordion: hide the tab bar, show a header per
    section, and reveal only the open section's body. Open state is acc-open
    (can be none — tap the open header again to collapse), separate from the
    desktop is-active tab so the desktop single-panel view never goes blank. */
 .secTabsWrap{display:none}
 .secPanel{display:block;margin-top:0;padding-top:0;border-top:1px solid var(--border)}
 .secPanel:first-of-type{border-top:0}
 .secAccHead{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;appearance:none;border:0;background:transparent;color:var(--ink);font:inherit;font-size:17px;font-weight:600;letter-spacing:-.01em;padding:.82rem .1rem;cursor:pointer;text-align:left;min-height:52px}
 .secAccHead .secChev{display:inline-grid;place-items:center;flex:0 0 34px;width:34px;height:34px;border-radius:999px;background:var(--panel2);color:var(--accent);font-size:22px;line-height:1;transition:transform .15s,background .15s,color .15s}
 .secAccHead[aria-expanded="true"] .secChev{transform:rotate(90deg);background:var(--accent-bg);color:var(--accent)}
 .secAccHead:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:8px}
 .secPanelBody{display:none;padding-bottom:.7rem}
 .secPanel.acc-open .secPanelBody{display:block}
 .wrap{padding:1.6rem .55rem 3rem}
 .hero{min-height:clamp(300px,64vh,440px)}
 /* Top pad clears the fitted hero map (100/2.4 = 41.6vw tall, pinned to the top
    of the hero on phones - see the .hwLegend block above). */
 .heroContent{padding:calc(41.6vw + 1rem) .8rem 1.6rem}
 .heroToggle{top:.6rem;right:.6rem}
 .hero .lede{font-size:15.5px}
 h1{font-size:27px}
 .lede{font-size:15.5px}
 .shead p{font-size:13.5px}
 section{margin-top:2rem;padding-top:1.5rem}
 /* 16px inputs stop iOS from zooming the page on focus */
 .agerange select,.phsearch input,.ptsel select{font-size:16px;padding:.5rem .6rem}
 /* stack the passport/floor/focus controls so each gets a full, non-overflowing row */
 .indexControls{flex-direction:column;align-items:stretch}
 .indexControls .budgetRow,.indexControls .ptsel,.indexControls .visaStep{width:100%;flex:0 0 auto}
 .indexControls .ptsel select{flex:1}
 .agerange{flex-wrap:wrap}
 /* finger-friendly tap targets */
 /* Range thumbs: 15px is a mouse target, not a finger one. 26px on every slider the
    site ships (age dual-range, fit weights, budget, research premiums). The taller
    input/track heights are load-bearing — a thumb bigger than its input box gets
    clipped in WebKit, and the -11px margin re-centres it on the 4px track
    ((26-4)/2). The .dualTrack copies must be repeated: that selector is more
    specific than the bare `input[type=range]` one and would otherwise keep 15px. */
 input[type=range]{height:28px}
 input[type=range]::-webkit-slider-thumb{width:26px;height:26px;margin-top:-11px}
 input[type=range]::-moz-range-thumb{width:26px;height:26px}
 .dualTrack{height:34px}
 /* The two stacked inputs must keep filling the track box — the `height:28px` above
    has the same specificity as the base `.dualTrack input{height:100%}` and, being
    later in the file, was winning and leaving the thumbs 3px off-centre. */
 .dualTrack input[type=range]{height:100%}
 .dualTrack input[type=range]::-webkit-slider-thumb{width:26px;height:26px;margin-top:-11px}
 .dualTrack input[type=range]::-moz-range-thumb{width:26px;height:26px}
 .seg button{padding:.55rem .8rem;font-size:13px;white-space:nowrap}
 .chips button,.miniBtn{padding:.5rem .8rem;font-size:12.5px}
 .maptools button{width:36px;height:36px}
 /* wide segmented controls swipe horizontally instead of wrapping/squishing */
 .seg{min-width:0;max-width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
 .seg::-webkit-scrollbar{display:none}
 .seg button{flex:0 0 auto}
 /* age dual-slider: stack label over a full-width track. As a flex item next to the
    Sweep button it shrank to its label width (72px measured at 375px) and the track
    ran into the button — force it onto its own full-width row. */
 .ageSlider{grid-template-columns:minmax(0,1fr);gap:6px;flex:1 1 100%;min-width:0}
 .ageSlider .dualRange,.ageSlider .dualTrack{min-width:0}
 .cityAgeRow{align-items:stretch}
 .cityAgeRow .seg{width:100%}
 .legend{margin-left:0;width:100%;justify-content:space-between}
 .legend .ramp,.legend .rampStep{flex:1}
 /* denser ranking table + smooth momentum scroll on the overflow wrapper */
 table{font-size:12.5px}
 th,td{padding:.45rem .5rem}
 [style*="overflow-x:auto"]{-webkit-overflow-scrolling:touch}
 /* keep hover tooltips inside the screen */
 #tip,#ptip{max-width:78vw;white-space:normal}
 .religionList,.pyrTop,.visaExtras,.liveExtras{grid-template-columns:1fr}
 .visaStat{flex:1 1 100%}
 .settleGrid{grid-template-columns:1fr}
 .scamGrid{grid-template-columns:1fr}
 .cmpGrid{grid-template-columns:1fr}
 .pyrAxis,.pyrRow{grid-template-columns:40px 1fr 40px 1fr 40px 34px;gap:5px}
 .pyrVal,.pyrAge{font-size:10.5px}
 .pyrSide{height:13px}
 .wxLegend{margin-left:0}
 .wxTable thead th:first-child{width:76px}
 .wxTable th[scope="row"]{font-size:11px}
 /* 16px or iOS zooms the whole page when the select takes focus */
 .relPick select{font-size:16px;max-width:none;flex:1}
 .relPick{width:100%}
 .visaPassSel select{font-size:16px;flex:1}
}

/* metric-label emoji: slightly smaller, a hair of space, non-selectable */
.mIcon{margin-right:.35em;font-size:.95em;line-height:1}
.lockIcon{display:inline-block;margin-right:.25em;font-size:.95em;line-height:1}
.shareIcon{display:inline-block;margin-right:.35em;font-size:.95em;line-height:1}

/* ---------- site header ---------- */
html{scroll-behavior:smooth}
.siteHeader{position:sticky;top:0;z-index:50;background:var(--panel);border-bottom:1px solid var(--border)}
/* Offset anchored sections so the sticky header doesn't cover their heading. */
#deepdives{scroll-margin-top:72px}
.siteHeaderInner{max-width:1000px;margin:0 auto;padding:.55rem 1.25rem;display:flex;align-items:center;gap:1rem;flex-wrap:wrap}
.brand{font-weight:700;font-size:18px;color:var(--ink);text-decoration:none;letter-spacing:-.01em}
.brand span{color:var(--accent)}
.siteNav{display:flex;gap:.25rem;margin-left:.5rem}
.siteNav a{color:var(--sub);text-decoration:none;font-size:14px;padding:.35rem .6rem;border-radius:8px;white-space:nowrap}
.siteNav a:hover{background:var(--panel2);color:var(--ink)}
.siteNav a.on{color:var(--ink);font-weight:600}
/* Theme toggle (js/theme.js). `margin-left:auto` lives here rather than on
   .authArea so the button is the first right-aligned item; .authArea keeps its
   own auto margin as a fallback for any page that loads without theme.js. */
.themeBtn{margin-left:auto;display:inline-flex;align-items:center;justify-content:center;
 width:36px;height:36px;padding:0;border:1px solid var(--border);border-radius:9px;
 background:var(--panel2);color:var(--ink);font-size:15px;line-height:1;cursor:pointer}
.themeBtn:hover{border-color:var(--accent);background:var(--accent-bg)}
.themeBtn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.themeBtn+.authArea{margin-left:0}
.authArea{margin-left:auto;display:flex;align-items:center;gap:.5rem;font-size:13px}
.authEmail{color:var(--sub);max-width:16ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acct{position:relative;display:flex;align-items:center}
.acctBtn{display:inline-flex;align-items:center;gap:.4rem;padding:.22rem .5rem .22rem .28rem;border:1px solid var(--border);background:var(--panel2);border-radius:999px;cursor:pointer;color:var(--sub);font:inherit;min-height:38px}
.acctBtn:hover,.acctBtn[aria-expanded="true"]{border-color:var(--accent);color:var(--ink)}
.acctBtn .proBadge{font-size:10px;padding:.16rem .4rem}
.acctAvatar{width:28px;height:28px;border-radius:50%;background:var(--accent);color:#fff;display:grid;place-items:center;font-weight:700;font-size:13px;flex:0 0 auto}
.acctAvatar.lg{width:40px;height:40px;font-size:17px}
.acctChev{color:var(--muted);transition:transform .15s ease}
.acctBtn[aria-expanded="true"] .acctChev{transform:rotate(180deg)}
/* Width is driven by the EMAIL, which is the one piece of content here we don't
   control the length of. 280px fits a typical address on one line (a 25-char
   address renders ~175px at 14px, and the avatar + gap + padding eat ~70px);
   the max lets a longer one grow before it has to wrap. 92vw keeps it on screen
   at 375px. */
.acctMenu{position:absolute;top:calc(100% + 8px);right:0;min-width:280px;max-width:min(380px,92vw);background:var(--panel);border:1px solid var(--border);border-radius:14px;box-shadow:0 12px 34px rgba(0,0,0,.22);padding:.5rem;z-index:60}
.acctMenu[hidden]{display:none}
.acctHead{display:flex;align-items:center;gap:.65rem;padding:.5rem .55rem .7rem;border-bottom:1px solid var(--border);margin-bottom:.4rem}
.acctWho{display:flex;flex-direction:column;min-width:0}
/* NOT word-break:break-all — that breaks at ANY character, so a perfectly
   ordinary address split as "kyle.mi.swanson@gmail." / "com". overflow-wrap:
   anywhere only breaks when the text genuinely cannot fit, so short addresses
   stay on one line and long ones wrap at the last possible point instead of
   mid-domain. The full address is always in the title attribute either way. */
.acctEmail{color:var(--ink);font-size:14px;font-weight:600;line-height:1.25;word-break:normal;overflow-wrap:anywhere}
.acctPlan{color:var(--muted);font-size:12px;margin-top:.12rem}
.acctItem{display:block;width:100%;text-align:left;background:none;border:0;font:inherit;font-size:14px;color:var(--sub);text-decoration:none;padding:.5rem .55rem;border-radius:8px;cursor:pointer}
.acctItem:hover{background:var(--panel2);color:var(--ink)}
.acctItem.danger{color:var(--warm)}
.acctItem.danger:hover{background:color-mix(in srgb,var(--warm) 14%,transparent);color:var(--warm)}
.authBtn{appearance:none;border:1px solid var(--accent);background:var(--accent);color:#fff;font:inherit;font-size:13px;padding:.34rem .7rem;border-radius:999px;cursor:pointer;text-decoration:none;white-space:nowrap;min-height:34px;display:inline-flex;align-items:center}
.authBtn:hover{filter:brightness(1.06)}
.authBtn.ghost{background:transparent;color:var(--sub);border-color:var(--border)}
.authBtn.ghost:hover{background:var(--panel2);color:var(--ink)}
.proBadge{background:var(--warm);color:#fff;font-size:11px;font-weight:700;letter-spacing:.05em;padding:.22rem .45rem;border-radius:6px}

/* ---------- shared site footer (injected by footer.js) ---------- */
.siteFooter{margin-top:3rem;border-top:1px solid var(--border);background:var(--panel);font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;color:var(--sub)}
.siteFooterInner{max-width:1000px;margin:0 auto;padding:2.2rem 1.25rem 1.6rem;display:grid;grid-template-columns:1.6fr 1fr 1fr 1fr;gap:1.5rem 2rem}
.sfBrand .brand{font-size:18px}
.sfBrand p{margin:.5rem 0 0;font-size:13px;line-height:1.55;max-width:42ch;color:var(--muted)}
.sfCol{display:flex;flex-direction:column;gap:.15rem}
.sfCol h4{margin:0 0 .45rem;font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);font-weight:600}
.sfCol a{color:var(--sub);text-decoration:none;font-size:14px;padding:.25rem 0;border-radius:6px}
.sfCol a:hover{color:var(--accent)}
.sfCol a.sfDiscord{display:inline-flex;align-items:center;gap:.45rem}
.sfCol a.sfDiscord svg{flex:0 0 auto;opacity:.85}
.sfBar{max-width:1000px;margin:0 auto;padding:.9rem 1.25rem 1.6rem;border-top:1px solid var(--border);display:flex;flex-wrap:wrap;gap:.3rem 1rem;justify-content:space-between;align-items:center;font-size:12px;color:var(--muted)}
.sfDisc{opacity:.9}
@media (max-width:640px){
 .siteFooterInner{grid-template-columns:1fr 1fr;gap:1.3rem 1rem;padding:1.8rem .8rem 1.2rem}
 .sfBrand{grid-column:1/-1}
 .sfBar{padding:.8rem .8rem 1.4rem}
}

/* ---------- auth / pro page ---------- */
.authPage .lede{margin-bottom:.4rem}
.authGrid{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin-top:1.6rem}
.authCard{padding:1.4rem}
.authH{margin:0 0 1.1rem;font-size:16px}
.googleBtn{display:flex;align-items:center;justify-content:center;gap:.6rem;width:100%;box-sizing:border-box;background:#fff;color:#3c4043;border:1px solid #dadce0;border-radius:10px;padding:.6rem 1rem;font:inherit;font-size:15px;font-weight:600;text-decoration:none;cursor:pointer;min-height:44px;transition:box-shadow .15s,background .15s}
.googleBtn:hover{box-shadow:0 1px 3px rgba(60,64,67,.3);background:#f8f9fa}
.gIcon{flex:0 0 auto}
.authDivider{display:flex;align-items:center;gap:.75rem;color:var(--muted);font-size:12px;margin:1.1rem 0}
.authDivider::before,.authDivider::after{content:"";flex:1;height:1px;background:var(--border)}
.authRow{display:flex;gap:.5rem}
.authRow input{flex:1;min-width:0;font-size:16px;padding:.55rem .7rem;border-radius:9px;border:1px solid var(--border);background:var(--bg);color:var(--ink)}
.authRow input:focus{outline:2px solid var(--accent);outline-offset:0;border-color:var(--accent)}
.btnPrimary{appearance:none;border:1px solid var(--accent);background:var(--accent);color:#fff;font:inherit;font-size:14px;font-weight:600;padding:.55rem 1rem;border-radius:9px;cursor:pointer;white-space:nowrap;min-height:44px}
.btnPrimary:hover{filter:brightness(1.06)}
.btnGhost{appearance:none;border:1px solid var(--border);background:transparent;color:var(--ink);font:inherit;font-size:14px;font-weight:600;padding:.55rem 1rem;border-radius:9px;cursor:pointer;min-height:44px}
.btnGhost:hover{background:var(--panel2)}
.btnUnlock{border-color:var(--warm);background:var(--warm)}
.authActions{display:flex;gap:.6rem;flex-wrap:wrap}
.authStatus{font-size:14px;color:var(--ink);margin:0 0 1rem}
.authMlHint{margin:.45rem 0 0}
.authMsg{margin:.85rem 0 0}
.authMsg a{color:var(--accent);font-weight:600}
.proData{white-space:pre-wrap;overflow-x:auto;font-size:12.5px;background:var(--panel2);border:1px solid var(--border);border-radius:9px;padding:.7rem;margin:1rem 0 0}
.proData:empty{display:none}
@media (max-width:640px){.authGrid{grid-template-columns:1fr}}
/* ---- Redesigned /pro pricing page ---- */
.proPage .lede{margin-bottom:.4rem}
/* "What you unlock" proof band — sits BELOW the price so the buy button stays high.
   Full content width so it balances the price/sign-in row above it (a narrow block
   under a wide row read lopsided). */
.proPreview{margin:1.8rem 0 0;border:1px solid var(--border);border-radius:14px;background:var(--panel);padding:1.2rem 1.3rem}
.proPreviewHead{text-align:center;max-width:52ch;margin:0 auto}
.proPreviewHead h2{margin:0 0 .2rem;font-size:18px;letter-spacing:-.01em}
.proPreviewHead p{margin:0 0 1rem;font-size:13.5px;color:var(--sub)}
/* Table + map side by side on desktop, stacked on a phone. */
.proPreviewGrid{display:grid;grid-template-columns:1fr;gap:.7rem}
@media(min-width:560px){.proPreviewGrid{grid-template-columns:1.15fr .85fr;align-items:stretch;max-width:780px;margin:0 auto}}
.proPreviewFrame{position:relative;overflow:hidden;border:1px solid var(--border);border-radius:10px;background:var(--bg)}
/* Blurred deep-dive map teaser. */
.proPreviewMap{position:relative;overflow:hidden;border:1px solid var(--border);border-radius:10px;background:var(--bg);display:flex;align-items:center;justify-content:center;min-height:120px}
.ppMapImg{display:block;width:100%;height:auto;filter:blur(5px) saturate(1.1);transform:scale(1.06);opacity:.9}
.ppMapOverlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;padding:.7rem;
 background:radial-gradient(ellipse at center,transparent,var(--bg) 92%)}
/* When the score table can't load (no-Functions server), pro.js drops it and marks
   the grid map-only — collapse to a single centred column so the map isn't a lonely
   block in a half-empty two-column grid (the "looks odd" report). */
.proPreviewGrid.mapOnly{grid-template-columns:1fr!important;max-width:460px}
/* Deep-dive section list — concrete "here's what's inside" chips. */
.proTabList{margin:1rem auto 0;max-width:720px;text-align:center}
.proTabIntro{margin:0 0 .55rem;font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);font-weight:700}
.proTabChips{display:flex;flex-wrap:wrap;gap:.4rem;justify-content:center}
.proTabChips span{font-size:12.5px;color:var(--ink);background:var(--bg);border:1px solid var(--border);
 border-radius:999px;padding:.28rem .6rem;line-height:1.1;white-space:nowrap}
.proPreviewTable{width:100%;border-collapse:collapse;font-size:13.5px}
.proPreviewTable th{text-align:left;font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:700;padding:.5rem .7rem;border-bottom:1px solid var(--border)}
.proPreviewTable th.scCol,.proPreviewTable td.scCol{text-align:right;font-variant-numeric:tabular-nums}
.proPreviewTable td{padding:.5rem .7rem;border-bottom:1px solid var(--border)}
.proPreviewTable tbody tr:last-child td{border-bottom:0}
.proPreviewTable .ppCity b{color:var(--ink)}
.proPreviewTable .ppCity span{color:var(--muted);font-size:12px}
.proPreviewTable .ppRank{color:var(--muted);font-variant-numeric:tabular-nums;width:2.2rem}
.proPreviewTable td.scCol b{color:var(--accent);font-weight:800;font-size:15px}
/* Locked rows: real cities, blurred so the ranking below the fold reads as "there's
   more here" without handing it over legibly. pointer/select off so it can't be
   dragged clear. */
.proPreviewTable .ppLock{filter:blur(4.5px);user-select:none;pointer-events:none}
.proPreviewTable .ppLock td.scCol b{color:var(--sub)}
/* Fade + lock CTA sitting over the last blurred rows. */
.proPreviewFade{position:absolute;left:0;right:0;bottom:0;display:flex;justify-content:center;align-items:flex-end;
 padding:.9rem;min-height:96px;background:linear-gradient(180deg,transparent,var(--bg) 78%)}
.proPreviewLockPill{display:inline-flex;align-items:center;gap:.4rem;font-size:12.5px;font-weight:600;color:var(--ink);
 background:var(--panel);border:1px solid var(--accent);border-radius:999px;padding:.35rem .7rem;box-shadow:0 4px 14px rgba(0,0,0,.18)}
.proPreviewLockPill b{color:var(--accent)}
.proGuarantee{font-size:12px;color:var(--muted);margin:.5rem 0 0;text-align:center}
.proGuarantee a{color:var(--sub);text-decoration:underline}
.proGuarantee a:hover{color:var(--accent)}
@media (max-width:640px){.proPreview{padding:.9rem;margin-top:1rem}.proPreviewHead h2{font-size:15.5px}}
/* stretch, not start: the two cards were top-aligned and ended at different heights
   (pricing ran ~50px taller), leaving a ragged bottom edge. Equal height + the
   sign-in card's footer note pinned to its base (margin-top:auto below) reads clean. */
.proLayout{display:grid;grid-template-columns:1.15fr .85fr;gap:1rem;margin-top:1.6rem;align-items:stretch}
.proLayout>*{min-width:0}
.authCard{display:flex;flex-direction:column}
.authCard .proWhySignin{margin-top:auto;padding-top:1rem}
.proCard{padding:1.6rem}
.proStatus{font-size:13.5px;color:var(--sub);margin:0 0 1.1rem}
/* Post-payment banner for a PAY-FIRST buyer: the unlock is keyed to the email
   Stripe collected, so this has to be impossible to skim past — accent fill,
   not a muted note. .paidBannerAddr is the exact address to sign in with. */
.paidBanner{margin:0 0 1.2rem;padding:.85rem .95rem;border-radius:10px;
 background:var(--accent-bg);border:1px solid var(--accent);border-left-width:4px}
.paidBannerTop{display:flex;align-items:center;gap:.45rem;font-weight:700;
 font-size:14.5px;color:var(--accent);margin:0 0 .5rem}
.paidBannerAddr{display:block;font-weight:700;font-size:15px;color:var(--ink);
 word-break:break-all;margin:0 0 .45rem}
.paidBannerWhy{margin:0;font-size:12.5px;line-height:1.5;color:var(--sub)}
.proBadge{display:inline-block;background:var(--accent);color:#fff;font-size:11.5px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;padding:.3rem .6rem;border-radius:999px}
.proPriceRow{display:flex;align-items:baseline;gap:.6rem;margin:.9rem 0 .2rem;flex-wrap:wrap}
.proWas{font-size:20px;color:var(--muted);text-decoration:line-through}
.proNow{font-size:44px;font-weight:800;line-height:1;color:var(--ink)}
/* "once" rides the price itself — the number and the billing frequency read as one
   unit, so a skimmer who only sees the price still sees it is not per-month. */
.proPer{font-size:19px;font-weight:700;color:var(--sub);letter-spacing:.01em}
/* Full-width statement under the price, not muted fine print: buyers default to
   assuming a monthly SaaS, so this is the correction and has to carry weight. */
.proOnce{display:block;margin:.55rem 0 0;padding:.5rem .7rem;border-radius:8px;
 background:var(--accent-bg);border:1px solid var(--accent);
 font-size:13px;line-height:1.45;color:var(--sub)}
.proOnce b{color:var(--accent)}
.proFeatures{list-style:none;padding:0;margin:1.2rem 0 0;display:grid;gap:.55rem}
.proFeatures li{position:relative;padding-left:1.5rem;font-size:14px;color:var(--ink)}
.proFeatures li::before{content:"\2713";position:absolute;left:0;top:0;color:var(--accent);font-weight:800}
.proActions{display:flex;flex-direction:column;gap:.6rem;margin-top:1.4rem}
.btnBig{width:100%;box-sizing:border-box;font-size:15px;min-height:48px;display:inline-flex;align-items:center;justify-content:center}
.proFinePrint{font-size:11.5px;color:var(--muted);margin:.8rem 0 0;text-align:center}
.proWhySignin{margin:1rem 0 0}
/* The "email me updates" capture is its OWN card on a full-width row under the two
   cards, so the page background separates it the way it separates every other
   section. Inside the buy card (even with a big margin + divider) it still read as a
   step of the purchase. Full-bleed (1/-1) rather than column 1: under one column it
   left ~300px of dead space beside it. The shared .qSub (quiz) keeps its divider;
   here the card IS the separation. */
.proSubCard{grid-column:1/-1;margin-top:.7rem;padding:1.2rem 1.4rem}
.proSubCard #proSubscribe.qSub{margin-top:0;padding-top:0;border-top:0}
/* The band is full-width; the FORM is not. Unconstrained, the email field stretched
   to ~608px for one address and the blurb ran to a 768px line. */
.proSubCard .subForm{max-width:32rem}
.proUnlocked{text-align:center;padding:.6rem 0}
.proCheck{width:56px;height:56px;margin:0 auto .8rem;border-radius:999px;background:var(--panel2);border:2px solid var(--accent);color:var(--accent);font-size:28px;font-weight:800;display:flex;align-items:center;justify-content:center}
.proUnlockedH{margin:0 0 .3rem;font-size:22px}
.proUnlockedSub{margin:0 auto 1.2rem;max-width:34ch;font-size:14px;color:var(--sub)}
.proUnlocked .proData{text-align:left}
@media (max-width:760px){.proLayout{grid-template-columns:1fr}}
@media (max-width:640px){
 /* Two-row header: cramming brand + 4 nav links + theme + sign-in into one nowrap row
    forced everything to ~10px and still felt squished. Row 1 = brand (left) · theme +
    Sign in (right); Row 2 = the nav links full-width at a readable size. */
 .siteHeaderInner{padding:.5rem .7rem;gap:.4rem .5rem;flex-wrap:wrap}
 .brand{order:1;font-size:16px;flex:0 0 auto}
 .themeBtn{order:2;margin-left:auto;width:34px;height:34px;font-size:14px;flex:0 0 auto}
 .authArea{order:3;margin-left:0;flex:0 0 auto}
 /* Nav drops to its own full-width row, links spaced and legible; scrolls inside
    itself if a market ever adds enough links to overflow (never widens the page). */
 .siteNav{order:4;flex:0 0 100%;width:100%;margin:.1rem 0 0;gap:.15rem;flex-wrap:nowrap;
   overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}
 .siteNav::-webkit-scrollbar{display:none}
 .siteNav a{padding:.32rem .6rem;font-size:13.5px;flex:0 0 auto}
 .acctBtn{min-height:34px;padding:.18rem .4rem .18rem .22rem;gap:.3rem}
 .acctAvatar{width:27px;height:27px;font-size:12px}
 .authEmail{display:none}
 /* Pro page: tighten the vertical rhythm so the price + buy button sit within the
    first screen on a short phone (was ~770px down — below the fold on an iPhone SE).
    Compress the hero, shrink the oversized price, trim the card's inner spacing. */
 .proPage h1{font-size:24px;margin:.2rem 0 .3rem}
 /* The hero lede and the .proOnce band say the same thing; on a phone only one of
    them can be above the fold, so keep the one attached to the price. */
 .proPage .lede{display:none}
 .proLayout{margin-top:1rem;gap:.8rem}
 .proCard{padding:1.1rem}
 .proStatus{margin-bottom:.7rem}
 .proNow{font-size:34px}
 .proPer{font-size:16px}
 .proOnce{font-size:12.5px;padding:.45rem .6rem}
 .proFeatures{margin-top:.9rem;gap:.45rem}
 .proActions{margin-top:1rem}
}

/* ---------- fit quiz (homepage) ---------- */
.quizRow{display:flex;align-items:center;gap:.7rem;flex-wrap:wrap;margin:.9rem 0 0}
.quizCta{appearance:none;border:1px solid var(--accent);background:var(--accent);color:#fff;font:inherit;font-size:14.5px;font-weight:600;padding:.6rem 1.1rem;border-radius:999px;cursor:pointer;min-height:40px}
.quizCta:hover{filter:brightness(1.06)}
/* Discord recruit CTA — Discord blurple so it reads as a distinct "join" action next to the quiz. */
.discordCta{display:inline-flex;align-items:center;gap:.5rem;border:1px solid #5865F2;background:#5865F2;color:#fff;text-decoration:none;font-size:14.5px;font-weight:600;padding:.6rem 1.1rem;border-radius:999px;min-height:40px;box-sizing:border-box}
.discordCta:hover{filter:brightness(1.08)}
.discordCta svg{flex:0 0 auto}
.siteNav a.navDiscord{color:#5865F2;font-weight:600}
.siteNav a.navDiscord:hover{background:#5865F2;color:#fff}
.quizChipOn{font-size:12.5px;color:var(--accent);font-weight:600}
.paidOk{color:var(--accent);font-weight:700}
/* Pro upgrade CTA banner (homepage + country pages) → hosted Stripe on /pro */
.proBanner{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem 1rem;margin:.2rem 0 1.4rem;padding:.75rem 1rem;border:1px solid var(--border);border-radius:12px;background:var(--panel)}
.proBanner p{margin:0;font-size:13.5px;color:var(--sub);flex:1 1 260px}
.proBanner b{color:var(--ink)}
.proCtaBtn{appearance:none;border:1px solid var(--accent);background:var(--accent);color:#fff;font:inherit;font-size:14px;font-weight:600;padding:.5rem .95rem;border-radius:999px;text-decoration:none;white-space:nowrap;min-height:40px;display:inline-flex;align-items:center;justify-content:center}
.proCtaBtn:hover{filter:brightness(1.06)}
@media (max-width:640px){.proCtaBtn{width:100%}}
.qChipLink{appearance:none;border:none;background:none;color:var(--muted);font:inherit;font-size:12.5px;text-decoration:underline;cursor:pointer;padding:.3rem;min-height:36px}
/* modal lives outside .wrap, so it re-declares the font stack */
.quizOverlay{position:fixed;inset:0;z-index:90;background:rgba(10,12,10,.55);display:flex;align-items:center;justify-content:center;padding:1rem;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;line-height:1.55}
.quizOverlay[hidden]{display:none}
/* flex column + stable min-height so the body scrolls internally and the Back/
   Next row stays anchored at the same spot on every step — same-place clicking */
.quizModal{background:var(--panel);color:var(--ink);border:1px solid var(--border);border-radius:14px;width:100%;max-width:480px;max-height:92vh;min-height:min(540px,82vh);display:flex;flex-direction:column;padding:1rem 1.2rem 1.2rem}
.quizBody{flex:1 1 auto;overflow-y:auto;min-height:0}
.quizTop{flex:0 0 auto;display:flex;justify-content:space-between;align-items:center;color:var(--muted);font-size:12.5px}
.quizX{appearance:none;border:none;background:none;color:var(--muted);font-size:22px;cursor:pointer;line-height:1;padding:.2rem .5rem;min-width:36px;min-height:36px}
.quizX:hover{color:var(--ink)}
.qTitle{margin:.2rem 0 .8rem;font-size:17px}
.quizModal .note{font-size:12.5px;color:var(--sub)}
.qSelect{width:100%;font-size:16px;padding:.55rem .7rem;border-radius:9px;border:1px solid var(--border);background:var(--bg);color:var(--ink)}
.qChips{display:flex;flex-direction:column;gap:.5rem}
.qChip{appearance:none;border:1px solid var(--border);background:var(--panel2);color:var(--ink);font:inherit;font-size:14px;padding:.55rem .9rem;border-radius:10px;cursor:pointer;text-align:left;min-height:40px}
.qChip:hover{border-color:var(--accent)}
.qChip.on{border-color:var(--accent);background:var(--accent-bg);font-weight:600}
.qChip.sm{font-size:12.5px;padding:.4rem .6rem;min-height:36px;text-align:center}
.qPrioRow{display:flex;align-items:center;justify-content:space-between;gap:.6rem;padding:.4rem 0;border-bottom:1px dashed var(--border)}
.qPrioRow:last-of-type{border-bottom:none}
.qPrioLabel{font-size:14px;font-weight:600}
.qPrioChips{display:flex;gap:.35rem;flex-wrap:wrap;justify-content:flex-end}
.qBudget{display:flex;align-items:center;gap:.8rem}
.qBudget input{flex:1;min-width:0}
.qBudget output{font-weight:700;min-width:88px;text-align:right}
.quizNav{flex:0 0 auto;display:flex;justify-content:space-between;gap:.6rem;margin-top:1rem;padding-top:.9rem;border-top:1px solid var(--border)}
/* class display:flex would otherwise beat the [hidden] attribute — keep the
   result screen simple: no Back / "See my results" nav, just the map CTA */
.quizNav[hidden]{display:none}
.quizBtn{appearance:none;border:1px solid var(--accent);background:var(--accent);color:#fff;font:inherit;font-size:14px;font-weight:600;padding:.55rem 1rem;border-radius:9px;cursor:pointer;min-height:40px}
.quizBtn:hover{filter:brightness(1.06)}
.quizBtn.ghost{background:transparent;color:var(--ink);border-color:var(--border)}
.quizBtn.ghost:hover{background:var(--panel2)}
.quizBtn:disabled{opacity:.4;cursor:default}
.qResGrid{display:grid;grid-template-columns:1fr 1fr;gap:1rem;margin:.4rem 0}
.qResGrid h4{margin:.2rem 0 .4rem;font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
.qResList{margin:0;padding-left:1.2rem;font-size:14px}
.qResList li{margin:.25rem 0}
.qDim{color:var(--muted);font-size:12px}
.qScore{float:right;font-weight:700;color:var(--accent)}
.qActions{display:flex;align-items:center;gap:.9rem;flex-wrap:wrap;margin-top:.8rem}
.qActions .quizBtn{font-size:15px;padding:.6rem 1.2rem}
.qLink{appearance:none;border:none;background:none;color:var(--muted);font:inherit;font-size:13px;text-decoration:underline;cursor:pointer;padding:.4rem .2rem;min-height:36px}
.qLink:hover{color:var(--ink)}
/* ---------- single-city metrics popup ---------- */
.cityOverlay{position:fixed;inset:0;z-index:95;background:rgba(10,12,10,.55);display:flex;align-items:center;justify-content:center;padding:1rem;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;line-height:1.5}
.cityOverlay[hidden]{display:none}
.cityModal{position:relative;background:var(--panel);color:var(--ink);border:1px solid var(--border);border-radius:14px;width:100%;max-width:460px;max-height:92vh;display:flex;flex-direction:column;overflow:hidden}
.cityModalX{position:absolute;top:.5rem;right:.5rem;z-index:2;appearance:none;border:none;background:rgba(0,0,0,.35);color:#fff;font-size:20px;line-height:1;cursor:pointer;width:32px;height:32px;border-radius:999px;display:flex;align-items:center;justify-content:center}
.cityModalX:hover{background:rgba(0,0,0,.55)}
.cityModalXText{display:none}
.cityModalHead{position:relative;flex:0 0 auto}
.cityModalHead .ccArt{width:100%;height:96px;object-fit:cover;display:block}
.cmHeadText{position:absolute;left:.9rem;bottom:.5rem;right:.9rem;color:#fff;text-shadow:0 1px 3px rgba(0,0,0,.6)}
.cmHeadText h3{margin:0;font-size:19px}
.cmHeadText p{margin:.1rem 0 0;font-size:12.5px;opacity:.95;display:flex;align-items:center;gap:.4rem;flex-wrap:wrap}
.cmHero{position:absolute;top:.5rem;left:.9rem;background:rgba(0,0,0,.4);color:#fff;border-radius:10px;padding:.3rem .55rem;text-align:center;line-height:1.1}
.cmHero b{font-size:20px;display:block}
.cmHero span{font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;opacity:.9}
.cityModalBody{flex:1 1 auto;overflow-y:auto;min-height:0;padding:.4rem .9rem}
.cdGroup{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);font-weight:700;margin:.7rem 0 .1rem;padding-top:.5rem;border-top:1px solid var(--border)}
.cdGroup:first-child{border-top:none;padding-top:.1rem;margin-top:.2rem}
.cdRow{display:flex;justify-content:space-between;align-items:baseline;gap:.8rem;padding:.42rem 0;border-bottom:1px solid var(--border);font-size:13.5px}
.cdRow:last-child{border-bottom:none}
.cdK{color:var(--sub);flex:0 0 auto}
.cdV{font-weight:600;text-align:right;border-radius:6px;padding:0 .3rem}
.cdV.dim{color:var(--muted);font-weight:400}
.cdV a{color:var(--warm);text-decoration:none}
.cdSub{display:block;font-size:10.5px;font-weight:400;color:var(--muted);margin-top:1px}
.cityModalFoot{flex:0 0 auto;display:flex;flex-direction:column;gap:.5rem;padding:.8rem .9rem;border-top:1px solid var(--border);background:var(--panel2)}
.cdDeep{display:block;text-align:center;background:var(--accent);color:#fff;font-size:14.5px;font-weight:600;padding:.6rem 1rem;border-radius:10px;text-decoration:none}
.cdDeep:hover{filter:brightness(1.06)}
.cdDeepPro{background:var(--warm)}
.cdCompare{appearance:none;border:1px solid var(--border);background:transparent;color:var(--ink);font:inherit;font-size:13px;font-weight:600;padding:.45rem 1rem;border-radius:9px;cursor:pointer;min-height:36px}
.cdCompare:hover{background:var(--panel)}
.cdCompare.on{border-color:var(--warm);color:var(--warm)}

/* ---------- compare: sticky bar + popup (home.js) ----------
   The bar replaces the old auto-scroll: selecting a city no longer moves the page,
   the bar just counts the selection and opens the popup on demand.
   Left-anchored, and the right edge stops short of feedback.js's #fbBtn (fixed
   bottom-right, 16px inset) so the two never overlap on a phone. */
.cityCmpBar{position:fixed;left:12px;right:12px;bottom:16px;z-index:90;display:flex;align-items:center;
 justify-content:space-between;gap:.75rem;max-width:560px;margin:0 auto;padding:.55rem .55rem .55rem .9rem;
 border:1px solid var(--border);border-radius:999px;background:var(--panel);color:var(--ink);
 box-shadow:0 4px 18px rgba(0,0,0,.18);font-size:13px}
.cityCmpBar[hidden]{display:none}
.cityCmpBarCount{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cityCmpBarBtns{display:flex;align-items:center;gap:.4rem;flex:0 0 auto}
.cityCmpBar button{appearance:none;font:inherit;font-weight:600;border-radius:999px;cursor:pointer;
 min-height:36px;padding:.35rem .9rem}
.cityCmpBarClear{border:1px solid var(--border);background:transparent;color:var(--sub)}
.cityCmpBarClear:hover{color:var(--ink);border-color:var(--accent)}
.cityCmpBarOpen{border:1px solid var(--accent);background:var(--accent);color:var(--panel)}
.cityCmpBarOpen:disabled{opacity:.45;cursor:default}
/* Wider than the single-city modal — this one holds a table. */
.cityCmpModal{max-width:min(980px,96vw);max-height:92vh}
.cityCmpModalTop{display:flex;align-items:center;justify-content:space-between;gap:.5rem;
 padding:.7rem .9rem;border-bottom:1px solid var(--border);flex:0 0 auto}
.cityCmpModalX{appearance:none;border:none;background:transparent;color:var(--sub);font-size:22px;
 line-height:1;cursor:pointer;width:32px;height:32px;border-radius:999px}
.cityCmpModalX:hover{background:var(--panel2);color:var(--ink)}
/* No top padding: `position:sticky;top:0` pins the city-name row to the scrollport's
   PADDING-box edge, so any padding here becomes a strip the rows scroll through in
   full view, between the dialog title and the stuck header. The gap goes on
   .cityCmpTop instead, which scrolls away with the content. */
.cityCmpModalBody{flex:1 1 auto;min-height:0;overflow:auto;padding:0 .9rem 1rem}
.cityCmpModalBody .cityCmpTop{margin-top:.7rem}
/* Inside the popup the DIALOG scrolls, so the table must not cap its own height —
   otherwise two nested scrollers fight and the sticky header sticks to the inner one. */
.cityCmpModal .cityCmpScroll{max-height:none;overflow:visible}

/* mobile quiz overrides live HERE, after the base quiz rules — putting them in
   the main 640px block up top would lose the cascade to these later base rules */
@media (max-width:640px){
 .quizOverlay{padding:0;align-items:flex-end} /* bottom sheet */
 /* The sheet was pinned at the 540px desktop min-height, so a 812px phone left ~270px
    of black overlay above it while the question list scrolled inside. Grow the sheet
    to the screen instead. dvh where supported — mobile vh counts the retracted URL bar. */
 .quizModal{max-width:none;border-radius:14px 14px 0 0;max-height:94vh;min-height:min(680px,88vh)}
 @supports(height:1dvh){.quizModal{max-height:94dvh;min-height:min(680px,88dvh)}}
 .qResGrid{grid-template-columns:1fr}
 .qPrioRow{flex-direction:column;align-items:flex-start}
 .qPrioChips{justify-content:flex-start}
 .cityOverlay{padding:0;align-items:flex-end}
 .cityModal{max-width:none;border-radius:14px 14px 0 0;max-height:94vh}
 .cityModalX{top:.6rem;right:.65rem;width:auto;height:34px;padding:0 .72rem;gap:.3rem;border:1px solid rgba(255,255,255,.38);background:rgba(0,0,0,.55);font-size:13px;font-weight:700}
 .cityModalX span:first-child{font-size:18px;line-height:1}
 .cityModalXText{display:inline}
 /* Phone: the bar is the width of the screen minus the feedback bubble, and the
    count line drops to a bare number so the buttons keep their tap targets. */
 .cityCmpBar{left:10px;right:10px;bottom:12px;padding:.45rem .45rem .45rem .75rem;font-size:12.5px}
 .cityCmpBar button{padding:.35rem .7rem}
 .cityCmpModalBody{padding:0 .55rem 1rem}
 .cityCmpModalBody .cityCmpTop{margin-top:.6rem}
}
/* feedback.js injects #fbBtn fixed bottom-right. Its normal z-index is low so
   filters/dropdowns/bottom sheets layer above it; still hide it while a
   full-screen overlay owns the screen. */
body:has(.quizOverlay:not([hidden])) #fbBtn,
body:has(.cityOverlay:not([hidden])) #fbBtn,
body:has(.rsOverlay:not([hidden])) #fbBtn{display:none}
/* Same rule for the compare bar — any full-screen overlay owns the screen. */
body:has(.quizOverlay:not([hidden])) .cityCmpBar,
body:has(.cityOverlay:not([hidden])) .cityCmpBar{display:none}
/* …and the reverse: the feedback bubble yields to the compare bar. Measured — the
   bubble is ~108px wide, so reserving a gap on a 375px screen left the bar too
   narrow for its count line. The bubble comes straight back on Clear or on open. */
body:has(.cityCmpBar:not([hidden])) #fbBtn{display:none}

/* ================= Research desk (dashboard) ================= */
.rsApp{max-width:1440px;margin:0 auto;padding:1.2rem 1.1rem 3rem;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;color:var(--ink)}
.rsIntro h1{margin:.2rem 0 .3rem;font-size:24px}
.rsIntro .note{max-width:80ch;font-size:13px}
.rsTopbar{display:flex;flex-wrap:wrap;gap:.8rem;align-items:flex-end;justify-content:space-between;margin:1rem 0 .8rem;padding:.7rem .8rem;background:var(--panel);border:1px solid var(--border);border-radius:12px}
.rsLens{display:flex;flex-wrap:wrap;gap:.7rem 1rem;align-items:flex-end}
.rsLensLabel{display:flex;flex-direction:column;justify-content:center;min-height:38px;padding-right:.2rem}
.rsLensLabel b{font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--ink)}
.rsLensLabel span{font-size:11px;color:var(--muted);white-space:nowrap}
.rsLctl{display:flex;flex-direction:column;gap:3px;font-size:11px;color:var(--sub);position:relative}
.rsLctl select{font-size:14px;padding:.35rem .5rem;border-radius:8px;border:1px solid var(--border);background:var(--bg);color:var(--ink)}
.rsLctl b{color:var(--ink)}
.rsBud input{width:130px}
.rsAff{flex-direction:column;gap:4px;align-items:flex-start}
.rsAffChip{font:inherit;font-size:11px;font-weight:600;color:var(--sub);background:var(--panel2);border:1px solid var(--border);border-radius:8px;padding:.32rem .5rem;cursor:pointer;white-space:nowrap}
.rsAffChip b{color:var(--ink);font-size:12.5px;margin-left:3px}
.rsAffChip:hover{border-color:var(--accent)}
.rsSeg{display:inline-flex;border:1px solid var(--border);border-radius:8px;overflow:hidden}
.rsSeg button{font:inherit;font-size:11px;font-weight:600;color:var(--sub);background:var(--bg);border:0;border-right:1px solid var(--border);padding:.3rem .55rem;cursor:pointer;line-height:1.2}
.rsSeg button:last-child{border-right:0}
.rsSeg button.on{background:var(--accent);color:#fff}
.rsAges{flex-direction:row;align-items:center;gap:.5rem;flex-wrap:wrap}
.rsAges .rsAgeTrack{width:150px;flex:0 0 150px}
.rsPrioPop{position:absolute;top:100%;left:0;margin-top:6px;z-index:20;background:var(--panel);border:1px solid var(--border);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.2);padding:.6rem .7rem;min-width:230px;max-height:60vh;overflow:auto}
.rsRunwayPop{position:absolute;top:100%;left:0;margin-top:6px;z-index:21;background:var(--panel);border:1px solid var(--border);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.2);padding:.65rem .7rem;min-width:230px;display:grid;grid-template-columns:1fr 1fr;gap:.55rem}
.rsRunwayPop[hidden]{display:none}
.rsRunwayPop label{display:flex;flex-direction:column;gap:3px;font-size:11px;color:var(--sub);font-weight:600}
.rsRunwayPop input{box-sizing:border-box;width:100%;font:inherit;font-size:13px;padding:.38rem .45rem;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--ink)}
.rsRunwayPop{max-height:72vh;overflow-y:auto;min-width:264px}
.rsRunwayPop select{box-sizing:border-box;width:100%;font:inherit;font-size:13px;padding:.38rem .45rem;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--ink)}
.rsPopSec{grid-column:1/-1;display:flex;justify-content:space-between;align-items:baseline;gap:.5rem;margin:.15rem 0 -.1rem;padding-top:.35rem;border-top:1px solid var(--border)}
.rsPopSec:first-child{border-top:0;padding-top:0}
.rsPopSec b{font-size:11.5px;color:var(--ink);text-transform:uppercase;letter-spacing:.04em}
.rsPopSec span{font-size:10px;color:var(--muted)}
.rsPortRow{grid-column:1/-1;display:grid;grid-template-columns:1fr 84px 56px 22px;gap:.4rem;align-items:center}
.rsPortRow span{font-size:11.5px;color:var(--sub);font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rsPortDel{border:1px solid var(--border);background:var(--bg);color:var(--muted);border-radius:6px;cursor:pointer;font-size:13px;line-height:1;padding:.3rem}
.rsPortDel:hover{color:var(--warm);border-color:var(--warm)}
.rsPortAdd{grid-column:1/-1;justify-self:start}
.rsHousing{grid-column:1/-1}
.rsHousePrem{display:flex;flex-direction:column;gap:5px;font-size:11px;color:var(--sub);font-weight:600}
.rsPremRow{display:flex;align-items:center;gap:.6rem}
.rsPremRow input[type=range]{flex:1;min-width:0;accent-color:var(--accent);cursor:pointer}
.rsPremOut{font-variant-numeric:tabular-nums;font-weight:700;color:var(--ink);font-size:12.5px;min-width:42px;text-align:right}
.rsCostBasis{display:flex;align-items:center;gap:.5rem;justify-content:space-between}
.rsCbLabel{font-size:11px;color:var(--sub);font-weight:600}
.rsBucketRow{grid-column:1/-1;display:grid;grid-template-columns:1fr 84px 22px;gap:.4rem;align-items:center}
.rsBucketRow input[type=text]{min-width:0}
@media (max-width:640px){.rsRunwayPop input,.rsRunwayPop select{font-size:16px}}
.rsPrioRow{display:flex;justify-content:space-between;align-items:center;gap:.6rem;padding:.28rem 0;font-size:13px}
.rsPrioChips{display:flex;gap:.25rem}
.rsPrioChip{appearance:none;border:1px solid var(--border);background:var(--panel2);color:var(--ink);font:inherit;font-size:11px;padding:.25rem .5rem;border-radius:7px;cursor:pointer}
.rsPrioChip.on{border-color:var(--accent);background:var(--accent-bg);color:var(--accent);font-weight:600}
.rsBarRight{display:flex;gap:.6rem;align-items:center;flex-wrap:wrap}
#rsSearch{font-size:15px;padding:.45rem .7rem;border-radius:9px;border:1px solid var(--border);background:var(--bg);color:var(--ink);min-width:200px}
.rsViews{display:inline-flex;border:1px solid var(--border);border-radius:9px;overflow:hidden}
.rsViews button{appearance:none;border:0;background:transparent;color:var(--sub);font:inherit;font-size:13px;padding:.45rem .8rem;cursor:pointer}
.rsViews button.on{background:var(--accent-bg);color:var(--accent);font-weight:600}
.rsMapCtl{display:inline-flex;align-items:center;gap:.4rem;font-size:12px;color:var(--sub)}
.rsMapCtl select{font:inherit;font-size:13px;padding:.35rem .55rem;border:1px solid var(--border);border-radius:8px;background:var(--panel);color:var(--ink)}
.rsMapBox{position:relative;border:1px solid var(--border);border-radius:12px;background:var(--bg);overflow:hidden}
#rsMap{min-height:360px}
#rsMap svg{background:linear-gradient(180deg,rgba(15,110,86,.06),transparent 55%)}
#rsMap path{cursor:pointer}
.rsMapTip{position:absolute;pointer-events:none;opacity:0;transform:translate(-50%,-118%);background:var(--panel);color:var(--ink);border:1px solid var(--border);box-shadow:0 8px 22px rgba(0,0,0,.22);font-size:12px;line-height:1.45;padding:7px 9px;border-radius:8px;white-space:nowrap;transition:opacity .08s;z-index:4}
.rsMapTip span{color:var(--muted)}
.rsMapLegend{display:flex;gap:.8rem;flex-wrap:wrap;align-items:center;margin:.65rem 0 0;font-size:12px;color:var(--muted)}
.rsMapLegend span{display:inline-flex;align-items:center;gap:.35rem}
.rsMapSwatch,.rsMapDotDemo{display:inline-block;width:10px;height:10px;border-radius:999px}
.rsMapGood{background:var(--accent)}
.rsMapMid{background:#b4530f}
.rsMapBad{background:#b23a2b}
.rsMapDotDemo{background:#8a93a6;opacity:.35;border:1px solid var(--border)}
.rsMapArcDemo{display:inline-block;width:16px;height:0;border-top:2px solid var(--accent);opacity:.7}
.rsMapRamp{display:inline-block;width:84px;height:10px;border-radius:999px;background:linear-gradient(90deg,#1d9e75,var(--mid,#c9a24a),#c0392b)}
.rsLegRamp{display:inline-block;width:80px;height:9px;border-radius:999px}
.rsLegEnd{color:var(--sub)}
.rsLegLine{display:inline-block;width:16px;height:0;border-top:2px solid;vertical-align:middle}
.rsLegDash{border-top-style:dashed}
/* map + shortlist side-by-side (the two-way link) */
.rsMapLayout{display:grid;grid-template-columns:1fr 220px;gap:.8rem;align-items:start}
.rsMapSide{max-height:430px;overflow-y:auto;border:1px solid var(--border);border-radius:10px;background:var(--bg);padding:.3rem}
.rsMapSideHead{font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);padding:.4rem .45rem;position:sticky;top:0;background:var(--bg);z-index:1}
.rsMapSideItem{display:flex;justify-content:space-between;gap:.5rem;width:100%;appearance:none;border:1px solid transparent;border-radius:8px;background:none;color:var(--ink);font:inherit;font-size:12.5px;text-align:left;cursor:pointer;padding:.35rem .45rem}
.rsMapSideItem:hover{background:rgba(127,127,127,.1)}
.rsMapSideItem.isFocus{background:var(--accent-bg);border-color:var(--accent)}
.rsMapSideName{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rsMapSideV{flex:0 0 auto;color:var(--sub);font-variant-numeric:tabular-nums}
/* focus ring shared by grid rows, map dots and pinboard cards */
.rsTable tbody tr.isFocus>td{background:var(--accent-bg)}
.rsScatterBox{position:relative;border:1px solid var(--border);border-radius:12px;background:var(--panel);padding:.3rem}
.rsWhy{background:var(--panel);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:10px;padding:.6rem .7rem;margin:0 0 .8rem}
.rsWhy h4{margin:0 0 .2rem;font-size:13px}
.rsWhyRow{display:flex;align-items:center;gap:.5rem;font-size:12px;margin:.22rem 0}
.rsWhyK{flex:0 0 44%;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rsWhyBar{flex:1;height:8px;background:var(--panel2);border-radius:5px;overflow:hidden}
.rsWhyBar i{display:block;height:100%;border-radius:5px}
.rsWhyV{flex:0 0 26px;text-align:right;font-weight:600;color:var(--ink)}
.rsDot{transition:stroke-width .08s}
.rsArcH{font-size:9px;font-weight:600;fill:var(--accent);text-anchor:middle;paint-order:stroke;stroke:var(--panel);stroke-width:2.5px;stroke-linejoin:round}
.rsHomeLabel{font-size:10px;font-weight:700;fill:var(--accent);paint-order:stroke;stroke:var(--panel);stroke-width:3px;stroke-linejoin:round}
.rsDot.isFocus{stroke:var(--ink);stroke-width:2.6px}
.rsCard.isFocus{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-bg)}
@media (max-width:760px){.rsMapLayout{grid-template-columns:1fr}.rsMapSide{max-height:220px}}
.rsShell{display:grid;grid-template-columns:250px 1fr;gap:1rem;align-items:start}
.rsRail{position:sticky;top:.7rem;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:.7rem .8rem;display:flex;flex-direction:column;gap:1rem}
.rsRailSec h4{margin:0 0 .5rem;font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
.rsRailHint{margin:-.25rem 0 .55rem;font-size:11.5px;line-height:1.35;color:var(--muted)}
.rsCount{font-size:11px;color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0}
.rsPinList{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.2rem;font-size:13px}
.rsPinList li{display:flex;align-items:center;gap:.4rem}
.rsPinDot{width:7px;height:7px;border-radius:999px;background:var(--accent);flex:0 0 auto}
.rsPinDot.country{background:var(--warm)}
.rsRailName{flex:1;appearance:none;border:0;background:none;color:var(--ink);font:inherit;font-size:13px;text-align:left;cursor:pointer;padding:.15rem 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rsRailName:hover{color:var(--accent)}
.rsRailX{appearance:none;border:0;background:none;color:var(--muted);font-size:15px;cursor:pointer;line-height:1;padding:0 .2rem}
.rsRailX:hover{color:var(--warm)}
.rsF{display:flex;flex-direction:column;gap:3px;font-size:12px;color:var(--sub);margin-bottom:.6rem}
.rsF select{font-size:14px;padding:.35rem .5rem;border-radius:8px;border:1px solid var(--border);background:var(--bg);color:var(--ink)}
.rsChk{display:flex;align-items:center;gap:.4rem;font-size:13px;color:var(--ink);cursor:pointer}
.rsMain{min-width:0;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:.9rem 1rem;min-height:60vh}
.rsMainHead{display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap;margin-bottom:.6rem}
.rsMainHead h2{margin:0;font-size:17px}
.rsHeadBtns{display:flex;gap:.5rem}
.rsEmpty{color:var(--muted);font-size:14px;padding:2rem 0;text-align:center}
/* overflow-x:auto alone would make this box the sticky-positioning root on BOTH
   axes (a CSS quirk: a non-visible value on one overflow axis forces the other
   to auto too), which stranded the sticky thead off-screen once the page
   scrolled. Giving it real vertical scroll + a bounded height fixes that: the
   header now sticks to the top of this panel as you scroll through rows,
   independent of the page's own scroll position. */
.rsTableWrap{overflow:auto;max-height:70vh}
.rsTable{width:100%;border-collapse:collapse;font-size:13px}
.rsTable th,.rsTable td{padding:.5rem .55rem;text-align:left;border-bottom:1px solid var(--border);white-space:nowrap}
.rsTable thead th{color:var(--sub);font-weight:600;font-size:12px;position:sticky;top:0;background:var(--panel);cursor:pointer;user-select:none;z-index:2}
.rsTable thead th.sortOn{color:var(--accent)}
.rsTable thead th.sortOn[data-dir="asc"]::after{content:" \25B2";font-size:9px}
.rsTable thead th.sortOn[data-dir="desc"]::after{content:" \25BC";font-size:9px}
/* discoverability: any sortable header hints it sorts (faint ↕) until it's active */
.rsTable thead th[data-sort]:not(.sortOn):hover::after{content:" \2195";font-size:9px;opacity:.55}
.rsTable tbody tr{cursor:pointer}
.rsTable tbody tr:hover{background:var(--panel2)}
.rsTable .idx{font-weight:700}
.rsName{font-weight:600}
.rsDim{color:var(--muted)}
.rsPin{appearance:none;border:0;background:none;color:var(--muted);font-size:15px;cursor:pointer;line-height:1;padding:0}
.rsPin.on{color:var(--warm)}
.rsSub{font-size:10.5px;color:var(--muted);font-weight:400}
.rsCmp th[scope="row"],.rsCmpMetric{color:var(--sub);font-weight:600;position:sticky;left:0;background:var(--panel);text-align:left}
.rsGroupRow th{font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);background:var(--panel2);padding-top:.5rem}
.rsCmpHead{display:flex;flex-direction:column;gap:2px;position:relative;padding-right:22px}
.rsCmpHead b{font-size:13px}
.rsCmpX{position:absolute;top:-3px;right:-4px;width:22px;height:22px;display:inline-flex;align-items:center;justify-content:center;appearance:none;border:1px solid var(--border);background:var(--panel);color:var(--muted);font:inherit;font-size:14px;line-height:1;padding:0;border-radius:999px;cursor:pointer;transition:color .12s,border-color .12s,background .12s}
.rsCmpX:hover{border-color:var(--warm);color:var(--warm);background:var(--panel2)}
.rsCmpX:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.rsCards{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:.8rem}
.rsCard{border:1px solid var(--border);border-radius:11px;padding:.7rem .8rem;background:var(--bg);display:flex;flex-direction:column;gap:.5rem}
.rsCardTop{display:flex;justify-content:space-between;align-items:flex-start;gap:.5rem}
.rsCardTop h3{margin:0;font-size:15px}
.rsCardTop p{margin:.1rem 0 0}
.rsCardScore{text-align:center;line-height:1.1}
.rsCardScore b{font-size:20px;color:var(--accent);display:block}
.rsCardScore span{font-size:9.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
.rsChips{display:flex;flex-wrap:wrap;gap:.3rem}
.rsChip{font-size:10.5px;background:var(--panel2);border-radius:6px;padding:.15rem .4rem;color:var(--sub)}
.rsChip b{color:var(--ink)}
.rsNote{width:100%;box-sizing:border-box;font:inherit;font-size:12.5px;min-height:44px;resize:vertical;border:1px solid var(--border);border-radius:8px;background:var(--panel);color:var(--ink);padding:.4rem .5rem}
.rsCardFoot{display:flex;gap:.4rem;align-items:center}
.rsStageMove{display:flex;gap:.2rem;margin-right:auto}
.rsStageMove .rsMini{padding:.3rem .45rem;min-height:28px}
/* decision board */
.rsBoard{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:.7rem;align-items:start}
.rsColZone{background:var(--panel2);border:1px solid var(--border);border-radius:12px;padding:.5rem .5rem .7rem;min-height:120px}
.rsColHd{font-size:12px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:700;padding:.2rem .3rem .5rem}
.rsColBody{display:flex;flex-direction:column;gap:.6rem;min-height:60px}
.rsColEmpty{text-align:center;font-size:12px;padding:1.2rem .4rem;border:1px dashed var(--border);border-radius:9px}
.rsColZone.rsDragOver{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
.rsCard.rsDragging{opacity:.45}
.rsBoard .rsCard{background:var(--panel);cursor:grab}
.rsCardTitle{display:flex;align-items:center;gap:.4rem}
.rsRank{font-size:11px;font-weight:700;color:var(--accent);background:var(--accent-bg);border-radius:6px;padding:.05rem .35rem}
.rsChip.up{background:var(--accent-bg);color:var(--accent)}
.rsChip.down{background:rgba(178,58,43,.14);color:var(--warm)}
.rsFacts{display:flex;flex-wrap:wrap;gap:.3rem}
.rsFact{font-size:10.5px;background:var(--panel2);border:1px solid var(--border);border-radius:6px;padding:.12rem .4rem;color:var(--sub)}
.rsBoard .rsFact{background:var(--bg)}
.rsFact.good{color:var(--accent);border-color:var(--accent)}
.rsFact.bad{color:var(--warm);border-color:var(--warm)}
.rsWhy{background:var(--panel);border:1px solid var(--border);border-left:3px solid var(--accent);border-radius:10px;padding:.55rem .8rem;margin:0 0 .9rem}
.rsWhy h3{margin:0 0 .25rem;font-size:13px}
.rsWhy h3 .rsDim{font-weight:500}
.rsWhy p{margin:0;font-size:13px;line-height:1.45}
.rsRunwayBox{border-left-color:var(--warm)}
.rsRunStats{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:.35rem;margin:.45rem 0 .5rem}
.rsRunStats span{background:var(--panel2);border:1px solid var(--border);border-radius:8px;padding:.35rem .4rem;min-width:0}
.rsRunStats b{display:block;color:var(--ink);font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rsRunStats em{display:block;color:var(--muted);font-size:10px;font-style:normal;text-transform:uppercase;letter-spacing:.04em;margin-top:1px}
.rsCostBars{display:flex;flex-direction:column;gap:.28rem;margin-top:.55rem}
.rsCostBar{display:grid;grid-template-columns:68px 1fr 54px;gap:.45rem;align-items:center;font-size:11.5px;color:var(--sub)}
.rsCostBar i{height:7px;background:var(--panel2);border-radius:999px;overflow:hidden}
.rsCostBar i b{display:block;height:100%;background:var(--warm);border-radius:999px}
.rsCostBar strong{text-align:right;color:var(--ink);font-weight:700}
.rsSpark{display:block;width:100%;height:auto;margin:.5rem 0 .15rem;overflow:visible}
.rsSparkCap{margin:.1rem 0 .4rem}
.rsSurv{display:flex;flex-wrap:wrap;gap:.3rem;margin:.15rem 0 .35rem}
.rsSurvCell{font-size:11px;font-weight:700;padding:.2rem .4rem;border-radius:6px;border:1px solid var(--border);white-space:nowrap}
.rsSurvCell.ok{color:#0f7a4a;border-color:#0f7a4a55;background:#0f7a4a14}
.rsSurvCell.no{color:var(--warm);border-color:var(--warm);background:#c0392b14}
:root[data-theme=dark] .rsSurvCell.ok{color:#4ad08a}
.rsPlanSummary{display:grid;grid-template-columns:repeat(auto-fit,minmax(96px,1fr));gap:.5rem;margin:.2rem 0 .6rem}
.rsPlanStat{background:var(--panel2);border:1px solid var(--border);border-radius:10px;padding:.5rem .6rem;min-width:0}
.rsPlanStat b{display:block;color:var(--ink);font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rsPlanStat em{display:block;color:var(--muted);font-size:10px;font-style:normal;text-transform:uppercase;letter-spacing:.04em;margin-top:1px}
.rsPlanList{display:flex;flex-direction:column;gap:.5rem;margin-top:.5rem}
/* ONE template shared by the header and every row, so a heading always sits over its
   own column. Two rules make the alignment robust:
     - minmax(0,Nfr) on the flexible tracks — a bare `Nfr` grows to its content's
       min-width, and the header (one word) and a row (4 stacked numbers) have DIFFERENT
       min-widths, so bare fr resolved the two grids to different sizes. That was the
       visible offset.
     - a FLEXIBLE minmax(0,Nfr) third track for the badge strip, NOT `auto`. `auto` sized
       to content — the word "horizon" (~50px) in the header vs a 246px badge strip in
       rows — so the two grids disagreed and the columns offset. A fr track resolves from
       CONTAINER width alone, so header and row compute it identically; the badges simply
       wrap to a second line when the pane is narrow instead of crushing the numbers (a
       fixed width did exactly that at small widths). ~1.6fr fits the 5 badges on one line
       at any pane wide enough to matter. */
:root{--rsPlanCols:minmax(0,1.3fr) minmax(0,2.4fr) minmax(0,1.6fr)}
.rsPlanRow{display:grid;grid-template-columns:var(--rsPlanCols);gap:.7rem;align-items:center;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:.6rem .75rem;cursor:pointer}
.rsPlanRow:hover,.rsPlanRow.isFocus{border-color:var(--accent);background:var(--panel2)}
.rsPlanCity b{display:block;color:var(--ink);font-size:14px}
.rsPlanCity span{display:block;color:var(--sub);font-size:11.5px}
/* Four fixed stats plus any picked columns (ws.planCols), so the track count is not
   fixed at 4 — auto-fit keeps every cell readable and wraps to a second line rather
   than crushing the numbers. Header and rows use the same rule, so they stay aligned. */
.rsPlanNums{display:grid;grid-template-columns:repeat(auto-fit,minmax(clamp(52px,20%,72px),1fr));gap:.4rem}
.rsPlanNums span{display:block;min-width:0}
.rsPlanNums b{display:block;color:var(--ink);font-size:13.5px;white-space:nowrap}
.rsPlanNums em{display:block;color:var(--muted);font-size:10px;font-style:normal;text-transform:uppercase;letter-spacing:.03em}
.rsPlanCov{border-radius:8px;padding:.15rem .35rem;margin:-.15rem -.05rem}
.rsPlanStrip{justify-content:flex-end}
/* Sortable header for the plan list. Uses the SAME --rsPlanCols template as .rsPlanRow
   (defined above) so the two can't drift — do not hardcode the tracks here. Padding
   matches the row minus its 1px border so the columns line up to the pixel. */
.rsPlanHead{display:grid;grid-template-columns:var(--rsPlanCols);gap:.7rem;align-items:end;
 padding:.35rem calc(.75rem + 1px);margin-top:.6rem}
.rsPlanHead .rsPlanNums{display:grid;grid-template-columns:repeat(auto-fit,minmax(clamp(52px,20%,72px),1fr));gap:.4rem}
/* Add-columns button above the plan list. Right-aligned so it reads as a control on
   the table below it, not part of the Monte Carlo card above. */
.rsPlanColBar{display:flex;justify-content:flex-end;margin-top:.7rem}
.rsPlanTh{display:block;color:var(--muted);font-size:10px;text-transform:uppercase;
 letter-spacing:.03em;cursor:pointer;user-select:none;white-space:nowrap}
.rsPlanTh:hover,.rsPlanTh.sortOn{color:var(--accent)}
.rsPlanTh:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:3px}
.rsPlanTh.sortOn[data-dir="asc"]::after{content:" \25B2";font-size:9px}
.rsPlanTh.sortOn[data-dir="desc"]::after{content:" \25BC";font-size:9px}
.rsPlanTh:not(.sortOn):hover::after{content:" \2195";font-size:9px;opacity:.55}
/* The header's horizon cell is a plain block (not the flex .rsSurv the rows use), so
   justify-content does nothing — text-align pins the label over the right-justified
   badge strip below it. */
.rsPlanHead .rsPlanStrip{font-size:10px;text-transform:uppercase;letter-spacing:.03em;text-align:right}
/* Mobile-only sort control — see planSortBarHtml(). Hidden wherever the clickable
   column header is shown, so exactly one sort UI is live at any width. */
.rsPlanSortBar{display:none;align-items:center;gap:.4rem;margin:.5rem 0 .4rem}
.rsPlanSortBar label{font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:700}
.rsPlanSortBar select{flex:1;min-width:0;font:inherit;font-size:16px;padding:.4rem .5rem;min-height:38px;border:1px solid var(--border);border-radius:8px;background:var(--panel);color:var(--ink)}
.rsPlanSortBar button{flex:0 0 auto;min-height:38px;white-space:nowrap}
@media (max-width:760px){.rsPlanRow{grid-template-columns:1fr;gap:.5rem}.rsPlanStrip{justify-content:flex-start}
 /* One column on mobile means a header row cannot align to anything — the rows stack
    and each cell already carries its own <em> label, so the header is pure noise.
    It was ALSO the only sort control, so the sort bar above takes over here. */
 .rsPlanHead{display:none}
 .rsPlanSortBar{display:flex}}
.rsRunwayNote{grid-column:1/-1;margin:.15rem 0 0;font-size:10.5px;line-height:1.4;color:var(--muted)}
/* Plan view: retirement planner (on-page inputs + Monte Carlo) */
/* minmax(0,1fr), not 1fr: a bare fr track keeps min-width:auto, so the results column
   grew to the plan list's min-content once picked columns (ws.planCols) pushed the row
   grid past the pane — and that overflowed the PAGE horizontally. */
.rsPlanShell{display:grid;grid-template-columns:300px minmax(0,1fr);gap:1rem;align-items:start;margin-top:.5rem}
@media (max-width:860px){.rsPlanShell{grid-template-columns:1fr}}
.rsPlanInputs{display:grid;grid-template-columns:1fr 1fr;gap:.55rem;align-content:start;background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:.7rem .8rem}
.rsPlanInputs label{display:flex;flex-direction:column;gap:3px;font-size:11px;color:var(--sub);font-weight:600}
.rsPlanInputs input,.rsPlanInputs select{box-sizing:border-box;width:100%;font:inherit;font-size:13px;padding:.38rem .45rem;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--ink)}
.rsPortRow3{grid-template-columns:1fr 66px 44px 44px 20px}
.rsMcCard{background:var(--panel);border:1px solid var(--border);border-radius:12px;padding:.8rem .9rem;margin-bottom:.6rem}
.rsMcHead{display:flex;justify-content:space-between;align-items:center;gap:.6rem;flex-wrap:wrap;margin-bottom:.5rem;min-width:0}
/* The city <select> is the widest thing in this card; let it shrink with the pane
   instead of pushing the card (and the page) wider than the viewport. */
.rsMcSel{min-width:0;max-width:100%}
.rsMcSel select{max-width:100%;min-width:0}
.rsMcHead>b{font-size:14px;color:var(--ink)}
.rsMcSel{font-size:11px;color:var(--sub);display:flex;gap:.35rem;align-items:center}
.rsMcSel select{font:inherit;font-size:13px;padding:.3rem .4rem;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--ink);max-width:200px}
.rsMcTop{display:flex;align-items:center;gap:.8rem;flex-wrap:wrap}
.rsMcBig b{font-size:34px;font-weight:700;line-height:1;color:var(--ink)}
.rsMcBig em{display:block;font-style:normal;font-size:11px;color:var(--muted);margin-top:2px}
.rsMcBig.ok b{color:#12925a}.rsMcBig.warn b{color:#c9820a}.rsMcBig.bad b{color:var(--warm)}
:root[data-theme=dark] .rsMcBig.ok b{color:#4ad08a}:root[data-theme=dark] .rsMcBig.warn b{color:#f0b64a}
.rsMcVerdict{font-size:12px;font-weight:700;padding:.25rem .6rem;border-radius:999px;border:1px solid}
.rsMcVerdict.ok{color:#12925a;border-color:#12925a55;background:#12925a14}
.rsMcVerdict.warn{color:#c9820a;border-color:#c9820a55;background:#c9820a14}
.rsMcVerdict.bad{color:var(--warm);border-color:var(--warm);background:#c0392b14}
:root[data-theme=dark] .rsMcVerdict.ok{color:#4ad08a}:root[data-theme=dark] .rsMcVerdict.warn{color:#f0b64a}
.rsMcPct{display:grid;grid-template-columns:repeat(3,1fr);gap:.4rem;margin:.4rem 0}
.rsMcPct span{background:var(--panel2);border-radius:8px;padding:.35rem .4rem;min-width:0}
.rsMcPct b{display:block;color:var(--ink);font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.rsMcPct em{display:block;font-style:normal;color:var(--muted);font-size:10px}
.rsMcFan{margin:.3rem 0}
.rsMcCell b{color:var(--ink)}
.rsMcCell.ok b{color:#12925a}.rsMcCell.warn b{color:#c9820a}.rsMcCell.bad b{color:var(--warm)}
:root[data-theme=dark] .rsMcCell.ok b{color:#4ad08a}:root[data-theme=dark] .rsMcCell.warn b{color:#f0b64a}
@media (max-width:640px){.rsPlanInputs input,.rsPlanInputs select{font-size:16px}}
@media (max-width:520px){.rsRunStats{grid-template-columns:repeat(2,minmax(0,1fr))}.rsRunwayPop{grid-template-columns:1fr;min-width:200px}}
@media (max-width:900px){.rsBoard{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:600px){.rsBoard{grid-template-columns:1fr}}
.rsMini{appearance:none;border:1px solid var(--border);background:var(--panel);color:var(--ink);font:inherit;font-size:12px;font-weight:600;padding:.35rem .7rem;border-radius:8px;cursor:pointer;text-decoration:none;display:inline-flex;align-items:center;min-height:32px}
.rsMini:hover{border-color:var(--accent)}
.rsMini.ghost{color:var(--sub)}
.rsMini.on{background:var(--accent-bg);color:var(--accent);border-color:transparent}
.rsMini.copied{background:var(--accent-bg);color:var(--accent);border-color:transparent}
.rsShareBuild{white-space:nowrap}
.rsOverlay{position:fixed;inset:0;z-index:90;background:rgba(10,12,10,.55);display:flex;align-items:center;justify-content:center;padding:1rem}
.rsOverlay[hidden]{display:none}
.rsModal{width:100%;max-width:420px;background:var(--panel);border:1px solid var(--border);border-radius:14px;box-shadow:0 18px 40px rgba(0,0,0,.28);overflow:hidden}
.rsModalTop{display:flex;justify-content:space-between;align-items:flex-start;gap:.75rem;padding:1rem 1rem .65rem;border-bottom:1px solid var(--border)}
.rsModalTop h3{margin:0;font-size:18px}
.rsModalX{appearance:none;border:0;background:none;color:var(--muted);font-size:22px;line-height:1;cursor:pointer;padding:.1rem .25rem}
.rsModalBody{padding:.9rem 1rem}
.rsModalField{display:flex;flex-direction:column;gap:.35rem;font-size:12px;font-weight:600;color:var(--sub);margin-top:.75rem}
.rsModalInput{width:100%;box-sizing:border-box;font:inherit;font-size:14px;padding:.65rem .75rem;border-radius:9px;border:1px solid var(--border);background:var(--bg);color:var(--ink)}
.rsModalInput:focus-visible{outline:2px solid var(--accent);outline-offset:-1px}
.rsModalFoot{display:flex;justify-content:flex-end;gap:.55rem;padding:.85rem 1rem 1rem;border-top:1px solid var(--border);background:var(--panel2)}
.rsDrawer{position:fixed;top:0;right:0;height:100vh;width:min(380px,92vw);z-index:80;background:var(--panel);border-left:1px solid var(--border);box-shadow:-8px 0 30px rgba(0,0,0,.22);display:flex;flex-direction:column;overflow:hidden}
.rsDrawer[hidden]{display:none}
.rsDrTop{display:flex;justify-content:space-between;align-items:flex-start;gap:.5rem;padding:.9rem 1rem;border-bottom:1px solid var(--border)}
.rsDrTop h3{margin:0;font-size:18px}
.rsDrTop p{margin:.1rem 0 0}
.rsDrX{appearance:none;border:0;background:none;color:var(--muted);font-size:22px;cursor:pointer;line-height:1;padding:.2rem .4rem}
.rsDrBody{flex:1;overflow-y:auto;padding:.4rem 1rem}
.rsDrGroup{font-size:10.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);font-weight:700;margin:.6rem 0 .1rem;padding-top:.4rem;border-top:1px solid var(--border)}
.rsDrGroup:first-child{border-top:none;padding-top:.1rem}
.rsDrRow{display:flex;justify-content:space-between;align-items:baseline;gap:.8rem;padding:.4rem 0;border-bottom:1px solid var(--border);font-size:13.5px}
.rsDrK{color:var(--sub)}
.rsDrV{font-weight:600;text-align:right;border-radius:6px;padding:0 .3rem}
.rsDrFoot{display:flex;gap:.5rem;padding:.8rem 1rem;border-top:1px solid var(--border);background:var(--panel2)}
@media (max-width:820px){
 .rsApp{overflow-x:hidden}
 .rsShell{grid-template-columns:1fr}
 .rsRail{position:static}
 .rsTopbar{flex-direction:column;align-items:stretch}
 .rsLens{width:100%}
 .rsLctl{min-width:0}
 .rsLctl select,.rsF select{max-width:100%;width:100%}
 .rsSeg button{padding:.5rem .8rem;font-size:12px;min-height:36px}
 .rsBud input{width:100%}
 .rsAges{width:100%}
 .rsAges .rsAgeTrack{flex:1;width:auto}
 .rsBarRight{width:100%;min-width:0;justify-content:space-between}
 #rsSearch{flex:1;min-width:0}
 .rsLens select,#rsSearch,.rsF select{font-size:16px}
 .rsOverlay{align-items:flex-end;padding:0}
 .rsModal{max-width:none;border-radius:14px 14px 0 0}
}

/* research desk — column picker + dynamic slicers + saved views */
.rsHeadBtns{align-items:center}
.rsColWrap{position:relative}
.rsColPop{position:absolute;top:100%;right:0;margin-top:6px;z-index:30;background:var(--panel);border:1px solid var(--border);border-radius:10px;box-shadow:0 10px 28px rgba(0,0,0,.25);padding:.6rem .7rem;width:250px;max-height:60vh;overflow-y:auto}
.rsColHead{font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:700;margin:.4rem 0 .3rem}
.rsColHead:first-child{margin-top:0}
.rsColSel{list-style:none;margin:0 0 .4rem;padding:0;display:flex;flex-direction:column;gap:.15rem}
.rsColSel li{display:flex;align-items:center;gap:.4rem;font-size:12.5px}
.rsColSel li span{flex:1}
.rsColMv,.rsColRm{appearance:none;border:1px solid var(--border);background:var(--panel2);color:var(--sub);font:inherit;font-size:11px;line-height:1;width:20px;height:20px;border-radius:5px;cursor:pointer;flex:none}
.rsColMv:disabled{opacity:.3;cursor:default}
.rsColName{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rsColDrag,.rsSlDrag{cursor:grab;color:var(--muted);font-size:13px;line-height:1;flex:none;user-select:none;touch-action:none}
.rsColHint{font-weight:400;text-transform:none;letter-spacing:0}
.rsColHeadRow{display:flex;align-items:center;gap:.4rem}
.rsColClear{margin-left:auto;appearance:none;font:inherit;font-size:10.5px;text-transform:none;letter-spacing:0;font-weight:600;color:var(--sub);background:var(--panel2);border:1px solid var(--border);border-radius:6px;padding:.15rem .45rem;cursor:pointer;flex:none}
.rsColClear:hover{color:var(--accent);border-color:var(--accent)}
.rsColClear:disabled{opacity:.45;cursor:default}
.rsColClear:disabled:hover{color:var(--sub);border-color:var(--border)}
.rsPopHead{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:.35rem .5rem;margin:0 0 .45rem;padding-bottom:.4rem;border-bottom:1px solid var(--border)}
.rsPopHead b,.rsPopHead>span{font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:700}
/* First bulk button takes the free space; the second (Add all + Remove all are a
   pair) sits flush against it instead of being pushed to the far edge. */
.rsPopHead .rsColClear{margin-left:auto}
.rsPopHead .rsColClear+.rsColClear{margin-left:0}
.rsPopX{appearance:none;border:1px solid var(--border);background:var(--panel2);color:var(--sub);font:inherit;font-size:18px;line-height:1;width:30px;height:30px;border-radius:999px;cursor:pointer;display:inline-grid;place-items:center;flex:0 0 auto;padding:0}
.rsPopX:hover{border-color:var(--accent);color:var(--accent)}
.rsColSel li[draggable="true"]{cursor:grab}
.rsColSel li.rsDragOver,.rsSlicer.rsDragOver{box-shadow:inset 0 0 0 2px var(--accent)}
.rsColSel li.rsDragging,.rsSlicer.rsDragging{opacity:.4}
.rsSlName{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rsSlMove{display:flex;gap:.15rem;flex:none}
.rsSlMv{appearance:none;border:1px solid var(--border);background:var(--panel2);color:var(--sub);font:inherit;font-size:11px;line-height:1;width:19px;height:19px;border-radius:5px;cursor:pointer}
.rsSlMv:disabled{opacity:.3;cursor:default}
.rsColRm:hover{border-color:var(--warm);color:var(--warm)}
.rsColGrp{font-size:10px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);margin:.4rem 0 .15rem}
.rsColOpt{display:flex;align-items:center;gap:.4rem;font-size:12.5px;padding:.15rem 0;cursor:pointer}
.rsSlicer{border:1px solid var(--border);border-radius:9px;padding:.4rem .55rem;margin-bottom:.5rem;background:var(--bg)}
.rsSlHead{display:flex;justify-content:space-between;align-items:center;font-size:12.5px;font-weight:600;margin-bottom:.3rem}
.rsSlX{appearance:none;border:0;background:none;color:var(--muted);font-size:14px;line-height:1;cursor:pointer;padding:0 .2rem}
.rsSlX:hover{color:var(--warm)}
.rsSlNum{display:flex;align-items:center;gap:.35rem}
.rsSlIn{width:100%;min-width:0;font-size:13px;padding:.3rem .4rem;border-radius:6px;border:1px solid var(--border);background:var(--panel);color:var(--ink)}
.rsSlHint{font-size:10px;color:var(--muted);margin-top:.2rem}
.rsSlCat{display:flex;flex-direction:column;gap:.15rem;max-height:150px;overflow-y:auto}
.rsSlOpt{display:flex;align-items:center;gap:.4rem;font-size:12.5px;cursor:pointer}
.rsSlEmpty{font-size:12px;margin:.2rem 0 .5rem}
.rsAddSl{width:100%;font-size:13px;padding:.35rem .5rem;border-radius:8px;border:1px solid var(--border);background:var(--bg);color:var(--ink)}
/* Add-slicer picker: same popup shell as "Add columns", anchored to the rail. The rail
   is only ~230px wide, so the popup is allowed to overflow it to the LEFT (right:0)
   rather than being crushed to the rail's width. */
.rsAddSlWrap{width:100%}
.rsAddSlBtn{width:100%;justify-content:center}
.rsSlPop{right:0;left:auto;min-width:250px;max-width:min(320px,92vw)}
/* Rows are buttons here (single-click add), not checkbox labels — reset the button
   chrome so they read identically to the column picker's options. */
.rsSlAddOpt{display:block;width:100%;text-align:left;appearance:none;border:0;background:none;font:inherit;cursor:pointer}
.rsSlAddOpt:hover{color:var(--accent)}
/* Search inside an open categorical slicer dropdown (Country, Language, Region…).
   Its scroll container has its own smaller padding, so it overrides the popup offsets. */
.rsSlSearch{position:sticky;top:-.35rem;margin-bottom:.35rem;box-shadow:0 0 0 .35rem var(--panel)}
@media (max-width:820px){
 /* Popovers become bottom sheets pinned to the viewport — position:absolute/fixed
    with top:auto used to drop them off-screen far below the fold. */
 /* padding-top:0 is load-bearing: a sticky top:0 header pins to the scrollport's
    padding edge, so the sheet's own .6rem top padding became a gap that rows
    scrolled through ABOVE the Remove-all / close header. The header supplies that
    padding itself instead. */
 .rsColPop,.rsPrioPop{position:fixed;left:0;right:0;bottom:0;top:auto;width:auto;max-width:none;margin:0;max-height:78vh;overflow:auto;border-radius:14px 14px 0 0;box-shadow:0 -8px 30px rgba(0,0,0,.35);z-index:60;padding-top:0}
 .rsPopHead{position:sticky;top:0;z-index:2;background:var(--panel);margin:0 -.7rem .55rem;padding:.65rem .75rem .55rem .9rem}
 /* Two sticky elements at top:0 = the search box hides under the header. On a
    bottom sheet the header is the one that must stay reachable. */
 /* Scoped, not bare .rsColSearch: the base rule is declared LATER in this file and
    would win the equal-specificity tie. */
 .rsColPop .rsColSearch,.rsPrioPop .rsColSearch{position:static}
 /* The header wraps on a phone. Ordered so row 1 is title + close (close stays
    top-right where a sheet's dismiss belongs) and the bulk buttons take row 2 at
    a real tap size — flex-wrap alone dropped the close button to row 2, far left. */
 .rsPopHead>span{order:1}
 .rsPopHead .rsPopX{order:2;margin-left:auto}
 /* Zero-height full-width break: keeps the two bulk buttons on ONE row together
    instead of one squeezing onto the title row and the other wrapping alone. */
 .rsPopHead::after{content:"";order:3;flex:0 0 100%;height:0}
 .rsPopHead .rsColClear,.rsPopHead .rsColClear+.rsColClear{order:4;margin-left:0}
 /* auto margin beats justify-content:space-between, which would otherwise fling
    the pair to opposite edges of their own row. */
 .rsPopHead .rsColClear+.rsColClear{margin-right:auto}
 .rsPopHead .rsColClear{font-size:13px;padding:.35rem .6rem;min-height:36px}
 .rsPopX{width:38px;height:38px;font-size:23px}
 .rsAddSl{font-size:16px}
 .rsSlIn{font-size:16px}
}

/* research desk — slider readout + categorical dropdown slicers */
.rsSlReadout{font-size:12.5px;text-align:center;margin:.1rem 0 .15rem;color:var(--ink)}
.rsSlTrack{margin:.1rem 0 .1rem}
.rsSlDrop{font-size:12.5px}
/* Passport tax trail — headline is the summary, the detail sits behind the caret so a
   long note (the US one is 5 sentences) doesn't push the Withdrawal inputs off screen. */
/* Span BOTH tracks of the .rsPlanInputs / .rsRunwayPop 2-col grid — same rule
   .rsRunwayNote and .rsPopSec use. Without it the note renders in one 130px column. */
.rsTaxTrail{grid-column:1/-1;margin:.35rem 0 .1rem}
.rsTaxTrail>summary{cursor:pointer;font-size:11.5px;color:var(--sub);line-height:1.45;list-style:none;padding:.1rem 0}
.rsTaxTrail>summary::-webkit-details-marker{display:none}
.rsTaxTrail>summary::before{content:"\25B8 ";color:var(--muted)}
.rsTaxTrail[open]>summary::before{content:"\25BE "}
.rsTaxTrail>summary b{color:var(--ink)}
.rsTaxTrail>summary:hover{color:var(--accent)}
.rsTaxTrail .rsRunwayNote{margin:.25rem 0 0}
.rsSlDrop>summary{cursor:pointer;padding:.35rem .5rem;border:1px solid var(--border);border-radius:7px;background:var(--panel);list-style:none;user-select:none}
.rsSlDrop>summary::-webkit-details-marker{display:none}
.rsSlDrop>summary::after{content:"\25BE";float:right;color:var(--muted)}
.rsSlDrop[open]>summary::after{content:"\25B4"}
.rsSlDropBody{max-height:160px;overflow-y:auto;padding:.35rem .2rem 0}

/* ---------- restored Research Desk and admin layout ---------- */
.rsApp{max-width:1760px;padding-inline:clamp(1.1rem,2.4vw,2.6rem)}
.rsBudLab{display:flex;justify-content:space-between;align-items:baseline;gap:.3rem}
.rsBudTag{font-style:normal;font-size:9px;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--muted)}
.rsBudRow.isYours .rsBudTag,.rsBudRow.isScaled .rsBudTag{color:var(--accent)}
.rsBudRow.isNoBase .rsBudTag{color:var(--warm)}
.rsBudIn{position:relative;display:block}
.rsBudIn input{padding-right:1.5rem!important}
.rsBudRow.isYours .rsBudIn input{border-color:var(--accent)}
.rsBudClr{position:absolute;top:50%;right:.25rem;transform:translateY(-50%);border:0;background:none;color:var(--muted);cursor:pointer;line-height:1;padding:.15rem .25rem;font-size:14px}
.rsBudClr:hover{color:var(--warm)}
.rsBudBtns{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:.4rem}
.rsLifeChks{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:.5rem .9rem}
.rsLifeChk{flex-direction:row!important;align-items:center;gap:.35rem;font-size:11.5px;color:var(--sub);font-weight:600;cursor:pointer}
.rsLifeChk input{width:auto!important;min-height:16px;accent-color:var(--accent)}
.rsRcCard{border:1px solid var(--border);border-radius:12px;background:var(--panel);padding:.7rem .8rem;margin:.6rem 0}
.rsRcWrap{overflow-x:auto}
.rsRcTable{width:100%;border-collapse:collapse;font-size:12.5px}
.rsRcTable td{padding:.32rem .4rem;border-top:1px solid var(--border);vertical-align:baseline}
.rsRcTable tr:first-child td{border-top:0}
.rsRcDet{color:var(--muted);font-size:11px;white-space:nowrap}
.rsRcAmt{text-align:right;font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}
.rsRcEst td{color:var(--muted)}
.rsRcWarn td{color:var(--warm);font-weight:600}
.rsIncRow{grid-template-columns:1fr 74px 74px 22px!important}
.rsIncRow select{box-sizing:border-box;width:100%;font:inherit;font-size:12px;padding:.3rem .2rem;border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--ink)}
.rsRcTot td{border-top:1.5px solid var(--ink);font-weight:700;color:var(--ink)}
.rsChipPop{position:absolute;top:100%;left:0;margin-top:6px;z-index:20;background:var(--panel);border:1px solid var(--border);border-radius:10px;box-shadow:0 8px 24px rgba(0,0,0,.2);padding:.6rem .7rem;min-width:250px;max-width:320px;max-height:60vh;overflow:auto}
.rsChipPop[hidden]{display:none}
.rsChipGrp{margin-bottom:.4rem}
.rsChipGrpH{font-size:10.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:700;margin:.3rem 0}
.rsPchip{appearance:none;font:inherit;font-size:13px;padding:.3rem .55rem;margin:.15rem .25rem .15rem 0;border:1px solid var(--border);border-radius:999px;background:var(--bg);color:var(--ink);cursor:pointer;white-space:nowrap;line-height:1.1}
.rsPchip:hover{border-color:var(--accent)}
.rsPchip.on{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600}
.rsChipFoot{margin-top:.5rem;padding-top:.5rem;border-top:1px solid var(--border)}
.rsScatterBox svg{max-height:min(76vh,720px)}
.rsScCtls{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem .9rem;margin:0 0 .6rem;padding:.5rem .6rem;background:var(--panel2);border:1px solid var(--border);border-radius:10px}
.rsScChk{display:inline-flex;align-items:center;gap:.35rem;font-size:12.5px;color:var(--ink);cursor:pointer;min-height:32px}
.rsScChk input{width:16px;height:16px;accent-color:var(--accent);cursor:pointer}
.rsScChk.isOff{opacity:.4;cursor:not-allowed}
.rsScSwatch{display:inline-block;width:11px;height:11px;border-radius:999px;flex:0 0 auto}
.rsScRamp{background:linear-gradient(90deg,#b23a2b,#b4530f,var(--accent))}
.rsScLabel{font-size:10px;fill:var(--sub);paint-order:stroke;stroke:var(--panel);stroke-width:2.6px;stroke-linejoin:round;pointer-events:none}
.rsCmp{width:auto}
.rsCmp td,.rsCmp th{max-width:220px}
.rsWdDraw{display:block;margin-top:.2rem;font-size:13px;line-height:1.4;color:var(--ink)}
/* Wider inputs column than the base rule. Same minmax(0,…) guard as line ~1830: with a
   bare 1fr the results track keeps min-width:auto and the plan list's min-content
   (which grows with picked columns) overflows the page. */
.rsPlanShell{grid-template-columns:minmax(240px,360px) minmax(0,1fr)}
.rsPortRow3{grid-template-columns:minmax(0,1fr) 78px 50px 50px 20px}
.rsPortRow3 input{min-width:0}
.rsPortTotal{margin-top:.15rem;padding-top:.45rem;border-top:1px solid var(--border)}
.rsPortTotal span:first-child{color:var(--ink);font-weight:700}
.rsPortTotal b{font-size:12.5px;color:var(--ink);padding:.38rem .1rem;text-align:left}
/* Sticky search inside a scrolling popup. Two details make it read as pinned rather
   than floating: `top:-.6rem` cancels the popup's own padding-top so the box sits
   flush against the popup's top edge when stuck, and the spread-only box-shadow paints
   a solid panel band around it — without that, list rows scrolled BEHIND the popup's
   padding and showed as a sliver above the search box. */
.rsColSearch{position:sticky;top:-.6rem;z-index:2;width:100%;box-sizing:border-box;font-size:13px;padding:.35rem .5rem;margin-bottom:.3rem;border-radius:8px;border:1px solid var(--border);background:var(--bg);color:var(--ink);box-shadow:0 0 0 .7rem var(--panel)}
.rsColNoMatch{font-size:12.5px;padding:.3rem 0}
@media (max-width:640px){
 .rsColSearch{font-size:16px}
 /* Scatter goes portrait on a phone (see renderScatter): the viewBox shrinks by
    375/560, so this label needs to grow to land back at a readable pixel size. */
 .rsScLabel{font-size:15px}
 .rsPchip{font-size:14px;padding:.45rem .7rem}
 .rsBudIn input{padding-right:2.2rem!important}
 .rsBudClr{min-width:36px;min-height:36px;font-size:16px}
 .rsPortRow3{grid-template-columns:1.7fr 1fr 1fr 28px;row-gap:.3rem}
 .rsPortRow3>span:first-child{grid-column:1/-1}
 /* Compare table: tighten like the homepage so more city columns fit before the
    wrapper scrolls. Base is nowrap + 220px cells (one city fills the screen); let
    cells wrap and cap their width instead. Sticky metric column stays narrow. */
 .rsCmp{font-size:12px}
 .rsCmp th,.rsCmp td{padding:.4rem .38rem;white-space:normal;max-width:112px;min-width:86px}
 .rsCmp .rsCmpMetric,.rsCmp th[scope="row"]{min-width:80px;max-width:104px;font-size:10.5px}
 .rsCmpHead{padding-right:19px}
 .rsCmpHead b{font-size:11.5px;line-height:1.15;overflow-wrap:anywhere}
 .rsCmpHead .rsDim{font-size:9.5px}
 .rsCmpX{width:19px;height:19px;font-size:12px}
}
@media (max-width:820px){
 .rsColPop,.rsPrioPop,.rsChipPop{position:fixed;left:0;right:0;bottom:0;top:auto;width:auto;max-width:none;margin:0;max-height:78vh;border-radius:14px 14px 0 0;box-shadow:0 -8px 30px rgba(0,0,0,.35);z-index:60}
 .rsLens select,#rsSearch,.rsF select,.rsMapCtl select{font-size:16px}
 .rsScCtls{gap:.55rem .7rem}
 /* Reclaim edge space on phones — the panels carry their own padding, so the app
    frame only needs a hair. overflow-x:hidden (set at 820 above) stays as a net. */
 .rsApp{padding-inline:.55rem}
 /* The 6-view switcher does not fit one row at 375px; a 3-col grid shows all six
    without clipping (base .rsViews is inline-flex + overflow:hidden, which cut ~60px). */
 .rsViews{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;width:100%;border:0;border-radius:0;overflow:visible}
 .rsViews button{border:1px solid var(--border);border-radius:8px;min-height:38px;text-align:center;justify-content:center}
 .rsViews button.on{border-color:transparent}
 /* Header control clusters (scatter X/Y axis pickers, column buttons) must wrap
    instead of running off the right edge. */
 .rsHeadBtns{flex-wrap:wrap;justify-content:flex-start}
 /* Trim the main panel's side padding on phones so tables/cards get more room. */
 .rsMain{padding-left:.6rem;padding-right:.6rem}
 /* The "restored layout" block re-declares .rsPlanShell as 2-col AFTER the mobile
    rule, clobbering it — re-assert single column here so Plan stacks on phones. */
 .rsPlanShell{grid-template-columns:1fr}
}

/* ---------- admin ---------- */
.adminPage{max-width:900px}
.adminPage h1{margin-bottom:1rem}
.adminPanel{padding:1.2rem;margin:0 0 1rem}
.adminPanel h2{margin:0 0 .45rem;font-size:18px}
.adminPanelHead{display:flex;align-items:flex-start;justify-content:space-between;gap:1rem;margin-bottom:.9rem}
.adminActions{display:flex;flex-wrap:wrap;gap:.55rem;align-items:center;margin-top:.85rem}
.adminForm{display:grid;gap:.75rem}
.adminForm label{display:flex;flex-direction:column;gap:.3rem;font-size:12px;font-weight:700;color:var(--sub)}
.adminForm input,.adminForm textarea{box-sizing:border-box;width:100%;font:inherit;font-size:14px;padding:.62rem .7rem;border:1px solid var(--border);border-radius:9px;background:var(--bg);color:var(--ink)}
.adminForm input:focus-visible,.adminForm textarea:focus-visible{outline:2px solid var(--accent);outline-offset:-1px}
.adminGrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.75rem}
.adminResult{margin:.9rem 0 0;max-height:420px;overflow:auto;border:1px solid var(--border);border-radius:9px;background:var(--bg);color:var(--ink);padding:.8rem;font-size:12px;line-height:1.45;white-space:pre-wrap}
.adminCampaigns{display:grid;gap:.65rem;margin-top:1rem}
.adminCampaignRow{display:grid;grid-template-columns:minmax(220px,1fr) minmax(420px,1.4fr);gap:.8rem;align-items:center;border:1px solid var(--border);border-radius:9px;background:var(--bg);padding:.75rem}
.adminCampaignRow>div:first-child{display:grid;gap:.18rem;min-width:0}
.adminCampaignRow a{font-size:12px;color:var(--accent);overflow-wrap:anywhere}
.adminCampaignRow span{font-size:12px;color:var(--sub)}
.adminCampaignDelete{justify-self:start;min-height:34px;padding:.35rem .65rem;font-size:12px}
.adminCampaignStats{display:grid;grid-template-columns:repeat(7,minmax(58px,1fr));gap:.45rem}
.adminCampaignStats span{display:grid;gap:.1rem;padding:.35rem;border:1px solid var(--border);border-radius:7px;background:var(--panel)}
.adminCampaignStats b{font-size:13px;color:var(--ink)}
.adminCampaignStats em{font-style:normal;font-size:10px;color:var(--muted)}
.btnGhost.danger{color:var(--warm);border-color:rgba(178,58,43,.45)}
.btnGhost.danger:hover{background:rgba(178,58,43,.12)}
button[aria-busy=true]{opacity:.7;cursor:wait}

/* Feedback inbox — cards, not a table, because this is the admin panel most
   likely to be read on a phone and a message body has no column width. */
#fbAdminList{display:grid;gap:.65rem}
.fbAdminCount{margin:0 0 .2rem}
.fbAdminCard{border:1px solid var(--border);border-left:3px solid var(--border);border-radius:9px;background:var(--bg);padding:.75rem;min-width:0}
.fbAdminCard.unread{border-left-color:var(--accent)}
.fbAdminMeta{display:flex;flex-wrap:wrap;gap:.35rem .7rem;align-items:baseline;font-size:12px}
.fbAdminWho{font-weight:700;color:var(--ink);overflow-wrap:anywhere}
.fbAdminWho em{font-style:normal;font-weight:400;color:var(--muted)}
.fbAdminTime{color:var(--muted)}
.fbAdminMsg{margin:.5rem 0 .4rem;font-size:14px;line-height:1.45;white-space:pre-wrap;overflow-wrap:anywhere}
.fbAdminUrl{font-size:12px;color:var(--accent);overflow-wrap:anywhere}
.fbAdminErrs{font-size:12px;color:var(--warm)}
.fbAdminCtx{margin-top:.4rem;font-size:12px;color:var(--sub)}
.fbAdminCtx summary{cursor:pointer;min-height:28px;padding:.25rem 0}
.fbAdminCtx pre{margin:.35rem 0 0;max-height:260px;overflow:auto;padding:.6rem;border:1px solid var(--border);border-radius:8px;background:var(--panel);font-size:11.5px;line-height:1.4;white-space:pre-wrap;overflow-wrap:anywhere}
.fbAdminRow{display:flex;flex-wrap:wrap;gap:.5rem;margin-top:.6rem}
.fbAdminRow .btnGhost{min-height:36px;padding:.4rem .7rem;font-size:12px;display:inline-flex;align-items:center;text-decoration:none}

@media (max-width:640px){
 .adminGrid{grid-template-columns:1fr}
 .adminCampaignRow{grid-template-columns:1fr}
 .adminCampaignStats{grid-template-columns:repeat(2,minmax(0,1fr))}
 .adminForm input,.adminForm textarea{font-size:16px}
 .adminActions .btnPrimary,.adminActions .btnGhost{width:100%;justify-content:center}
 .fbAdminRow .btnGhost{flex:1 1 auto;min-height:40px;justify-content:center}
}

/* ---- Food tab: cuisine block + food-scene bars ---- */
.cuisineWrap{display:grid;grid-template-columns:minmax(0,300px) minmax(0,1fr);gap:16px;align-items:start}
.cuisineFig{margin:0}
.cuisineImg{width:100%;height:auto;aspect-ratio:4/3;border-radius:10px;display:block;object-fit:cover;background:var(--mid)}
.cuisineHead{margin:0;font-size:15.5px;color:var(--ink)}
/* CC BY / CC BY-SA REQUIRE visible attribution, so this credit line is a licence
   obligation, not provenance decoration — it is the one source string allowed on screen.
   Do not hide it to tidy the layout. */
.cuisineCredit{margin:.4rem 0 0;font-size:11.5px;color:var(--muted);line-height:1.35}
.cuisineCredit a{color:var(--muted);text-decoration:underline}
.dishBtns{display:flex;flex-wrap:wrap;gap:.4rem;margin:0 0 .8rem}
.dishBtn,.pickBtn{font:inherit;font-size:13px;padding:.34rem .7rem;min-height:36px;border-radius:999px;
 border:1px solid var(--border);background:var(--panel2);color:var(--sub);cursor:pointer}
.dishBtn:hover,.pickBtn:hover{color:var(--ink);border-color:var(--muted)}
.dishBtn.on,.pickBtn.on{background:var(--accent);border-color:var(--accent);color:var(--panel);font-weight:600}
.dishName{margin:0;font-size:15px;color:var(--ink)}
.foodRow{display:grid;grid-template-columns:minmax(0,9rem) 1fr auto;gap:.6rem;align-items:center;font-size:13.5px;color:var(--sub);margin:.3rem 0}
.foodName{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.foodBarWrap{background:var(--mid);border-radius:6px;height:10px;overflow:hidden}
.foodBar{display:block;height:100%;background:var(--s1);border-radius:6px}
.foodNum{color:var(--ink);font-variant-numeric:tabular-nums}
@media (max-width:640px){
 .cuisineWrap{grid-template-columns:1fr}
 .foodRow{grid-template-columns:minmax(0,7rem) 1fr auto}
}

/* ---- Per-city price detail ---- */
/* Column flow, NOT a grid. Group row counts are very uneven (Eating out 6, Groceries 2,
   Income 1) and a grid row sizes to its tallest cell, so Leisure/Rent/Income could not
   start until Eating out ended — a band of dead space across the panel on desktop.
   Columns pack the next group straight into the gap; break-inside keeps a group whole. */
.priceGrid{column-width:230px;column-gap:1.4rem}
.priceGroup{break-inside:avoid;-webkit-column-break-inside:avoid;display:inline-block;width:100%;margin:0 0 1rem}
.priceGroup:last-child{margin-bottom:0}
.priceGroup h4{margin:0 0 .35rem;font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:var(--muted);font-weight:600}
.priceRow{display:flex;justify-content:space-between;gap:.6rem;align-items:baseline;
 font-size:13.5px;color:var(--sub);padding:.2rem 0;border-bottom:1px solid var(--border)}
.priceRow:last-child{border-bottom:0}
.priceRow b{color:var(--ink);font-variant-numeric:tabular-nums;white-space:nowrap}
/* Emoji sit in their own span so they never inherit the value's tabular-nums or bold,
   and are aria-hidden in the markup — the text label carries the meaning. */
.priceIco{font-style:normal;margin-right:.4rem;opacity:.9}
.priceGroup h4 .priceIco{margin-right:.3rem;opacity:.8}

/* ---- Email capture (js/subscribe.js) --------------------------------------
   One block styles both mount points (quiz result, /pro paywall). It reads as a
   quiet footer to the thing above it, never as the primary action — the quiz's
   ranking and the paywall's buy button both have to win the eye. */
.qSub{margin-top:1.1rem;padding-top:.95rem;border-top:1px solid var(--border)}
.subHead{margin:0 0 .2rem;font-size:15px}
.subBlurb{margin:0 0 .6rem;font-size:13px;color:var(--sub)}
.subRow{display:flex;gap:.5rem;flex-wrap:wrap}
/* 16px or iOS zooms the whole page on focus (see CLAUDE.md responsive rules). */
.subEmail{flex:1 1 12rem;min-width:0;font-size:16px;padding:.55rem .7rem;
  border:1px solid var(--border);border-radius:8px;background:var(--bg);color:var(--ink)}
.subBtn{font-size:15px;padding:.55rem 1rem;min-height:36px;border:0;border-radius:8px;
  background:var(--accent);color:#fff;cursor:pointer;white-space:nowrap}
.subBtn:disabled{opacity:.6;cursor:default}
.subConsent{display:flex;gap:.5rem;align-items:flex-start;margin-top:.55rem;
  font-size:12.5px;color:var(--sub);line-height:1.45}
/* The checkbox is a tap target, so it keeps a real size on touch. */
.subConsent input{margin-top:.15rem;width:18px;height:18px;flex:0 0 auto}
.subTs{margin-top:.5rem}
.subTs:empty{display:none}
.subMsg{margin:.45rem 0 0;font-size:13px;color:var(--warm);min-height:1em}
.subDone{margin-top:1.1rem;padding-top:.95rem;border-top:1px solid var(--border);
  font-size:14px;color:var(--sub)}
@media (max-width:640px){
 .subRow{flex-direction:column}
 .subBtn{width:100%}
}

/* ---- Channel scorecard (admin) --------------------------------------------
   Ten numeric columns will never fit 375px, so the table scrolls inside its own
   container — the page itself must not scroll sideways (CLAUDE.md responsive). */
.chanTotals{font-size:13.5px;color:var(--sub);margin:0 0 .7rem}
.chanTotals b{color:var(--ink)}
.chanScroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.chanTable{width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums;font-size:13.5px}
.chanTable th,.chanTable td{text-align:left;padding:6px 10px;border-bottom:1px solid var(--border);white-space:nowrap}
.chanTable th{color:var(--muted);font-weight:600;font-size:12px}
.chanTable .num{text-align:right}
/* The verdict tints the whole row: the point of the table is to be readable at a
   glance, not to be studied column by column. */
.chanTable tr.chan-keep td{background:hsl(150 58% 45% / .12)}
.chanTable tr.chan-kill td{background:hsl(2 62% 52% / .12)}
.chanTable tr.chan-fix td{background:hsl(34 80% 50% / .13)}
/* Temporary-protection split by sub-national unit (country.js renderMigrationSub).
   Long (380 powiaty), so the wrapper scrolls VERTICALLY inside a max-height and
   HORIZONTALLY on a phone — the page itself must never widen (see CLAUDE.md). */
.tblWrap{overflow-x:auto;-webkit-overflow-scrolling:touch;border:1px solid var(--border);
  border-radius:8px}
/* Refugee block inside the map's detail panel. Boxed off from the census stats above it
   because it is a DIFFERENT population — running the two together as one stat grid is
   exactly the conflation the copy is at pains to deny. */
.tpDet{margin:.8rem 0 0;padding:.6rem .7rem;border:1px solid var(--border);border-radius:8px;
  background:var(--accent-bg,transparent)}
.tpDetHead{font-weight:600;font-size:12.5px;margin:0 0 .35rem}
.tpTbl{width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums;font-size:13px}
.tpTbl th,.tpTbl td{text-align:left;padding:5px 9px;border-bottom:1px solid var(--border);
  white-space:nowrap}
.tpTbl th{position:sticky;top:0;z-index:1;background:var(--card,var(--bg));color:var(--muted);
  font-weight:600;font-size:11.5px}
.tpTbl td.num,.tpTbl th.num{text-align:right}
.tpTbl td.dim{color:var(--muted)}
.tpTbl tbody tr:last-child td{border-bottom:0}
/* The density bar sits BEHIND its own number rather than in a column of its own: at 380
   rows a separate bar column doubles the width for no extra information. */
.tpTbl td.num{position:relative}
.tpBar{position:absolute;left:0;bottom:0;height:2px;background:var(--accent,#5b8def);
  opacity:.55}
.chanBadge{display:inline-block;padding:1px 7px;border-radius:999px;font-size:11px;
  font-weight:700;letter-spacing:.04em}
.chanBadge-keep{background:hsl(150 58% 45% / .22);color:var(--accent)}
.chanBadge-kill{background:hsl(2 62% 52% / .2);color:#c0392b}
.chanBadge-fix{background:hsl(34 80% 50% / .22);color:var(--warm)}
.chanBadge-testing{background:var(--panel2);color:var(--muted)}
.chanWhy{display:block;font-size:11.5px;color:var(--muted);white-space:normal;max-width:22rem}
@media (prefers-color-scheme:dark){.chanBadge-kill{color:#e66767}}
