/* The results pages, on the brand variables in brand.css. Party colors are data colors and don't follow the brand. */
/* Type sizes, one job each (Kyle, 2026-10-31): 12px capitals (the reporting line, breadcrumbs); 14px gray secondary
   text and small labels (the source line, party names, the kicker, "Races to watch", map legends); 16px text, tables
   and controls; 18px section descriptions; 20px the subheading. The live updates feed has its own. */
/* Conservative: orange, the flame in the party's logo (Kyle, 2026-10-31; was brown). Working Families: green (Kyle, 2026-11-03,
   replacing purple, which readers with red-green color blindness couldn't tell from Democratic blue). */
:root{--dem:#1f4f9e;--rep:#b3261e;--wor:#16834a;--con:#ef6c33;--oth:#8c8c8c;--rule:#e5e0d6;
  /* Maps: two shades per party, darker for a margin of 10 points or more (checked for color-vision deficiency).
     Working Families and Conservative in the tables' green and orange (Kyle, 2026-11-02; green 2026-11-03): every
     party's shades stay apart from every other's under protanopia, deuteranopia, and tritanopia (simulated). */
  --dem-1:#6b98e4;--dem-2:#1f4f9e;--rep-1:#ef8f80;--rep-2:#b3261e;--wor-1:#a8e0b0;--wor-2:#16834a;--con-1:#f8c58e;
  --con-2:#ef6c33;--oth-1:#bdb8ae;--oth-2:#8c8c8c;--none:#efebe3;
  --tie:repeating-linear-gradient(45deg,#8c8c8c 0 2px,#fff 2px 5px)}
/* No serif in the interactive (Kyle): Knockout 32 for text, Knockout 54 for headlines; the site's header and footer
   keep their own fonts. */
body{font-family:var(--nyf-font-sans);color:var(--nyf-ink);margin:0;background:#fff}
/* The width of nysfocus.com's pages: a 1366px container, the text --nyf-gutter from its edge as on the site (24px on a
   phone, 32px from 1024px, 40px from 1280px: content 1286px). Spacing comes from brand.css's 8px scale (Decisions).
   The page starts a section's space (32px, 48px from 768px) below the nysfocus.com header (Kyle). */
main{box-sizing:border-box;max-width:1366px;margin:0 auto;padding:var(--nyf-section) var(--nyf-gutter) var(--nyf-space-6)}
h1,h2{font-family:var(--nyf-font-headline);font-weight:400;text-transform:uppercase;line-height:1.05;margin:var(--nyf-space-3) 0 var(--nyf-space-1)}
h1{font-size:clamp(30px,6vw,46px);margin:var(--nyf-space-half) 0 var(--nyf-space-3)}
/* The subheading under each headline (Kyle), spaced as nysfocus.com's article deks are: close under the headline, a
   reading size (20px, 23px on a wider screen, on 1.4 lines), then room before the page (32px, 48px). As wide as the
   page (Kyle: the site's 688px text column left half the page empty beside the results). */
h1:has(+ .dek){margin-bottom:var(--nyf-space-2)}
.dek{font-family:var(--nyf-font-sans);font-size:20px;line-height:1.4;color:var(--nyf-ink);margin:0 0 var(--nyf-space-4)}
@media (min-width:768px){.dek{margin-bottom:var(--nyf-space-6)}}
h2{font-size:24px}
h2 a{color:inherit;text-decoration:none}
a{color:var(--nyf-blue)}
.kicker,.reporting,.source,small,.lines,.districts,.prevnext,.card-title{font-family:var(--nyf-font-sans)}
/* Breadcrumbs as an article's categories on nysfocus.com (Kyle): Knockout 54 capitals, the yellow underline only on hover
   (sliding up into place, as the site's), over a pale yellow rule; a light "›" between them, since they're a path.
   Quieter than the site's (Kyle, 2026-10-31): 12px on every screen, in the site's dark gray (--nyf-grey-dark; 2026-11-04,
   replacing #343434, which wasn't a brand color), ink on hover */
.crumbs{display:inline-block;font-family:var(--nyf-font-headline);text-transform:uppercase;letter-spacing:-.025em;font-size:12px;line-height:1.25;
  padding-bottom:var(--nyf-space-3);border-bottom:2px solid var(--nyf-cream);margin:0 0 var(--nyf-space-3)}
.crumbs a{color:var(--nyf-grey-dark);white-space:nowrap;text-decoration-line:underline;text-decoration-color:transparent;text-decoration-thickness:2px;text-underline-offset:10px;transition:all .15s cubic-bezier(.4,0,.2,1)}
.crumbs a:hover,.crumbs a:focus-visible{color:var(--nyf-ink);text-underline-offset:4px;text-decoration-color:var(--nyf-yellow)}
.crumbs span{color:var(--nyf-grey);margin:0 var(--nyf-space-half)}
.kicker{text-transform:uppercase;letter-spacing:.04em;font-size:14px;margin:0;color:var(--nyf-grey-dark)}
.source{font-size:14px;color:var(--nyf-grey);margin-top:var(--nyf-section);border-top:1px solid var(--rule);padding-top:var(--nyf-space-2)}
/* Inside a race: tight steps. The heading, then 8px; the switch or the call note, then 16px; the table; 8px, how much has
   reported; 16px, "Detailed results". */
/* How much has reported (Kyle): in capitals, smaller, so it reads apart from the sentence-case lines around it. No
   added letter spacing: Knockout's capitals are wide, and it fits one line on a 390px phone ("47% … (3,993 of 8,495)") */
.reporting{font-size:12px;text-transform:uppercase;margin:var(--nyf-space-1) 0 0;color:var(--nyf-grey)}

.results{width:100%;border-collapse:collapse;font-size:16px}
.results th,.results td{padding:var(--nyf-space-1) var(--nyf-space-half);border-bottom:1px solid var(--rule);text-align:left;vertical-align:top}
.results thead th{font-family:var(--nyf-font-sans);font-weight:400;text-transform:uppercase;font-size:14px;color:var(--nyf-grey-dark)}
/* On a phone, no Votes column: each row's votes under its share, so the name keeps the width (Kyle, 2026-11-03). */
.results .v-under{display:none}
@media (max-width:599px){.results .v{display:none}.results .v-under{display:block;font-size:14px;color:var(--nyf-grey);white-space:nowrap}}
.results .num{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums;position:relative}
.results tbody th{font-weight:400}
.results .other{color:var(--nyf-grey)}
.lines{display:block;font-size:14px;color:var(--nyf-grey);font-weight:400;margin-top:var(--nyf-space-half)}
.bar{display:block;height:5px;margin-top:var(--nyf-space-half);margin-left:auto;max-width:100%}
.swatch{display:inline-block;width:.7em;height:.7em;border-radius:50%;margin-right:.4em;vertical-align:baseline}
/* In a results table, the color is a bar at the start of the row (Kyle), not a dot: it spans the name and the party
   under it, which start the same distance from it (a dot before the name set the name off from the party). In By
   Party, each line has its own bar in its party's color, and the name none. */
.results tbody th{padding-left:14px}
.results tbody th{position:relative}
.results tbody th>.swatch,.results .line-name>.swatch{position:absolute;left:0;top:var(--nyf-space-1);bottom:var(--nyf-space-1);width:4px;height:auto;border-radius:0;margin:0}
.results .line-name{position:relative}
.results .line-name>.swatch{left:-14px;top:0;bottom:0}
.dem{background:var(--dem)}.rep{background:var(--rep)}.wor{background:var(--wor)}.con{background:var(--con)}.oth{background:var(--oth)}

/* "By county" starts a section's width below the results (Kyle): as far as the toggle sits below the subheading (32px,
   48px from 768px) */
.by-county h2{margin-top:var(--nyf-section)}
.county-name{font-weight:700;margin-right:.4em}

.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(14rem,1fr));gap:var(--nyf-space-2)}
.card{display:block;border:1px solid var(--rule);border-top:4px solid var(--nyf-yellow);padding:var(--nyf-space-2);color:inherit;text-decoration:none}
.card:hover{background:var(--nyf-cream)}
.card-title{display:block;text-transform:uppercase;font-size:20px;margin-bottom:var(--nyf-space-half)}
.card-body small{display:block;color:var(--nyf-grey);margin-top:var(--nyf-space-half)}

.districts{width:100%;border-collapse:collapse;font-size:16px}
.districts tbody th{white-space:nowrap}
.districts th,.districts td{text-align:left;padding:var(--nyf-space-1) var(--nyf-space-half);border-bottom:1px solid var(--rule);font-weight:400}
.districts thead th{text-transform:uppercase;font-size:14px;color:var(--nyf-grey-dark)}
.districts .pctrep,.districts thead th:last-child{text-align:right;white-space:nowrap}

.map{width:100%;height:auto;display:block}
.map .land{fill:#e9e4da;stroke:#fff;stroke-width:1}
.map .hi{fill:var(--nyf-yellow);stroke:var(--nyf-ink);stroke-width:1.5}
.map.locator .land{stroke-width:.5}.map.locator .hi{stroke-width:1}
.map .ring{fill:none;stroke:var(--nyf-ink);stroke-width:2}
.prevnext{display:flex;justify-content:space-between;gap:var(--nyf-space-2);margin-top:var(--nyf-section);font-size:16px}
.seats{font-family:var(--nyf-font-sans);font-size:16px;margin:0 0 var(--nyf-space-2)}

/* A race: the table on the left, the map on the right (desktop); stacked, table first, on a phone */
/* A map taller than the table gives its extra height to the county list's row, not the table's, so "By county" sits a
   section below the results whatever the map's height */
.race-layout{display:grid;grid-template-columns:minmax(0,3fr) minmax(0,2fr);grid-template-areas:"table map" "list map";grid-template-rows:auto 1fr;column-gap:var(--nyf-space-5);align-items:start}
/* Columns side by side (table and map, the key races, a chamber's seats and map) sit 64px apart on a wide screen */
@media (min-width:1280px){.race-layout,.race-layout.home,.chamber-row{column-gap:var(--nyf-space-8)}}
.race-table{grid-area:table}.race-list{grid-area:list}.race-layout .race-map{grid-area:map}
@media (max-width:860px){.race-layout{grid-template-columns:minmax(0,1fr);grid-template-areas:"table" "map" "list";grid-template-rows:none}.race-layout .race-map{position:relative;margin-top:var(--nyf-section)}}
.view-toggle{display:inline-flex;border:1px solid var(--nyf-ink);margin:0 0 var(--nyf-space-2)}
.view-toggle button{font:inherit;font-family:var(--nyf-font-sans);font-size:16px;background:#fff;color:var(--nyf-ink);border:0;padding:var(--nyf-space-half) var(--nyf-space-2);cursor:pointer}
.view-toggle button[aria-pressed="true"]{background:var(--nyf-ink);color:#fff}
.results .line-name{display:block;font-family:var(--nyf-font-sans);font-size:14px;color:var(--nyf-grey)}
.results .line-more th{padding-top:var(--nyf-space-half)}
.race-map{margin:0;position:relative}
.results-map{width:100%;height:auto;display:block}
/* Every map's lines are in screen pixels, not map units, so a border is as wide on one map as on another (Kyle),
   however each map is scaled */
.map path,.map circle,.results-map path,.court-map path{vector-effect:non-scaling-stroke}
/* The shapes have no border of their own: results.js draws every border once, in a layer over them (.edges), so each is
   the same width; the hovered or tapped shape's goes on top, dark */
.results-map .areas path{stroke:none;cursor:pointer}
.results-map .edges{pointer-events:none}
.results-map .edges path{fill:none;stroke:#fff;stroke-width:1}
.results-map .edges path.hot{stroke:var(--nyf-ink);stroke-width:2}
.results-map .inset rect{fill:#fff;stroke:var(--nyf-grey);stroke-width:.75}
.results-map .inset text{font-family:var(--nyf-font-sans);font-size:13px;fill:var(--nyf-grey-dark)}
.f-none,.results-map path:not([class]){fill:var(--none)}.f-tie{fill:url(#tie-stripes)}
.f-dem-1{fill:var(--dem-1)}.f-dem-2{fill:var(--dem-2)}.f-rep-1{fill:var(--rep-1)}.f-rep-2{fill:var(--rep-2)}
.f-wor-1{fill:var(--wor-1)}.f-wor-2{fill:var(--wor-2)}.f-con-1{fill:var(--con-1)}.f-con-2{fill:var(--con-2)}
.f-oth-1{fill:var(--oth-1)}.f-oth-2{fill:var(--oth-2)}
.map-legend{display:flex;flex-wrap:wrap;gap:var(--nyf-space-half) var(--nyf-space-2);align-items:center;font-family:var(--nyf-font-sans);font-size:14px;margin:var(--nyf-space-2) 0 var(--nyf-space-half)}
.map-legend .key{display:inline-flex;align-items:center;gap:var(--nyf-space-half)}.map-legend .key[hidden]{display:none}
.map-legend i{display:inline-block;width:16px;height:12px}.map-legend i:last-of-type{margin-right:var(--nyf-space-half)}
.map-legend i.f-dem-1{background:var(--dem-1)}.map-legend i.f-dem-2{background:var(--dem-2)}
.map-legend i.f-rep-1{background:var(--rep-1)}.map-legend i.f-rep-2{background:var(--rep-2)}.map-legend i.f-none{background:var(--none)}.map-legend i.f-oth-1{background:var(--oth-1)}.map-legend i.f-oth-2{background:var(--oth-2)}.map-legend i.f-tie{background:var(--tie)}
.map-legend i.f-wor-1{background:var(--wor-1)}.map-legend i.f-wor-2{background:var(--wor-2)}.map-legend i.f-con-1{background:var(--con-1)}.map-legend i.f-con-2{background:var(--con-2)}
.race-map figcaption{font-family:var(--nyf-font-sans);font-size:14px;color:var(--nyf-grey);margin-top:var(--nyf-space-1)}
.map-tip{position:absolute;z-index:5;background:#fff;border:1px solid var(--nyf-ink);padding:var(--nyf-space-1) var(--nyf-space-1);font-family:var(--nyf-font-sans);font-size:14px;max-width:260px;pointer-events:none;box-shadow:0 2px 8px rgb(0 0 0/.12)}
.map-tip strong{display:block;font-size:16px}.map-tip small{display:block;color:var(--nyf-grey)}
.share{white-space:nowrap;margin-right:var(--nyf-space-1)}
.map-tip .share{display:block;margin:0}
/* A hover card's results: a row per candidate, the party dot before the last name, votes and share in columns */
.tip-table{border-collapse:collapse;margin:var(--nyf-space-half) 0;font-size:14px}
.tip-table th{font-weight:400;text-align:left;white-space:nowrap;padding:1px 0}
.tip-table td{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap;padding:1px 0 1px var(--nyf-space-2)}
.swatch.blank{visibility:hidden}

/* The county list as a table: sortable headers, a share with its votes under it */
.county-table{width:100%;border-collapse:collapse;font-size:16px}
.county-table th,.county-table td{padding:var(--nyf-space-1) var(--nyf-space-half);border-bottom:1px solid var(--rule);text-align:left;vertical-align:top}
.county-table thead th{font-family:var(--nyf-font-sans);font-weight:400;text-transform:uppercase;font-size:13px;color:var(--nyf-grey-dark);white-space:nowrap}
.county-table thead button{font:inherit;color:inherit;text-transform:inherit;background:none;border:0;padding:0;cursor:pointer}
.county-table thead th[aria-sort="ascending"] button::after{content:"\00a0▲";font-size:10px}   /* kept with its label (Kyle, 2026-11-05) */
.county-table thead th[aria-sort="descending"] button::after{content:"\00a0▼";font-size:10px}
.county-table .num{text-align:right;font-variant-numeric:tabular-nums}
.county-table td small{display:block;font-size:13px;color:var(--nyf-grey)}
.county-table tbody th{font-weight:700;white-space:nowrap}
.county-table tr.flash{animation:flash 1.6s ease-out}
@keyframes flash{from{background:var(--nyf-cream)}to{background:transparent}}
/* By Party: space between a candidate's name and their first line, and each line's numbers level with its name */
.results.by-line tr:not(.line-more) .line-name{margin-top:var(--nyf-space-1)}
.results.by-line th,.results.by-line td{vertical-align:bottom}
/* Zoomed maps: the districts around (context), the district's outline over its county parts, a state locator */
.results-map .context{fill:#f6f3ee;stroke:#d9d4ca;stroke-width:1}
.results-map .outline{fill:none;stroke:var(--nyf-ink);stroke-width:2.5;pointer-events:none}
.results-map path[data-href]{cursor:pointer}
.locator-wrap{width:38%;max-width:180px;margin-top:var(--nyf-space-1)}
.race-map .map{width:100%;height:auto;display:block}
.race-map .map .land{fill:#e9e4da;stroke:#fff;stroke-width:1}
.race-map .map .hi{fill:var(--nyf-yellow);stroke:var(--nyf-ink);stroke-width:1.5}
/* Race calls: a checkmark after the winner's name, and who called it under the table. Not in bold (Kyle, 2026-11-03):
   the font kit has Knockout 32 in one weight, so a browser fakes bold, and it looked smeared. */
/* The winner's checkmark, after the name everywhere (Kyle, 2026-11-03); who called it on hover, focus or tap */
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.win{position:relative;display:inline-block;font-family:var(--nyf-font-sans);font-weight:700;color:var(--nyf-ink);cursor:help;outline-offset:2px}
/* Tooltips (a winner's ✓, an incumbent's "(i)", a House race's Cook rating), on hover, focus or a tap: at most 12.5rem
   wide, so a long one takes two lines (Kyle, 2026-11-03); centered over what was pointed at, and kept 8px inside the
   screen by results.js, which sets --tip-x (Kyle, 2026-11-03: on a phone a ✓ near the left edge pushed its tooltip off
   the screen). Without it, simply centered. */
.win::after,.inc::after,.rating::after,.tv-name::after{content:attr(data-tip);position:absolute;left:var(--tip-x,50%);transform:var(--tip-t,translateX(-50%));bottom:calc(100% + 6px);z-index:10;width:max-content;max-width:12.5rem;
  background:var(--nyf-ink);color:#fff;font-family:var(--nyf-font-sans);font-size:13px;font-weight:400;line-height:1.3;letter-spacing:0;padding:var(--nyf-space-half) var(--nyf-space-1);white-space:normal;text-transform:none;text-align:left;
  opacity:0;visibility:hidden;transition:opacity .12s;pointer-events:none}
.win:hover::after,.win:focus::after,.inc:hover::after,.inc:focus::after,.rating:hover::after,.rating:focus::after,.tv-name:hover::after,.tv-name:focus::after{opacity:1;visibility:visible}
/* An incumbent's "(i)" (Kyle), after the name: what it means shows as the checkmark's does. */
.inc{font-family:var(--nyf-font-sans);font-weight:400;color:var(--nyf-grey);cursor:help;text-decoration:underline dotted;text-underline-offset:3px;outline-offset:2px;white-space:nowrap;position:relative}
/* A House race's Cook Political Report rating (Kyle, 2026-11-03): an info mark after the race's heading on the home
   page, the rating in its tooltip. */
.rating{position:relative;display:inline-flex;vertical-align:middle;margin-left:var(--nyf-space-1);color:var(--nyf-grey);cursor:help;outline-offset:2px}
.rating:hover,.rating:focus{color:var(--nyf-ink)}
/* The race call, under the reporting line and styled as it (Kyle, 2026-11-03). */
.call-note{font-family:var(--nyf-font-sans);font-size:12px;text-transform:uppercase;margin:var(--nyf-space-half) 0 0;color:var(--nyf-grey)}

/* The live updates feed (site/feed.js; Kyle). Nothing shows until it has posts (feed.js sets .has-feed on .feed-host); the
   results take the width until then. */
.feed-panel,.feed-fab,.feed-backdrop{display:none}
/* The panel's head: "LIVE UPDATES" with a red LIVE label, then when it was updated and whose posts these are */
.feed-head{position:sticky;top:0;z-index:3;background:#fff;padding:var(--nyf-space-2) 0 var(--nyf-space-1);border-bottom:3px solid var(--nyf-yellow);margin:0 0 var(--nyf-space-1)}
.feed-head-row{display:flex;align-items:center;justify-content:space-between;gap:var(--nyf-space-2)}
.feed-head h2{margin:0;font-size:26px;display:flex;align-items:center;gap:var(--nyf-space-1)}
.live-label{font:700 11px/1 var(--nyf-font-sans);letter-spacing:.08em;color:#fff;background:var(--nyf-red);border-radius:3px;padding:4px 6px 3px;display:inline-flex;align-items:center;gap:5px}
.live-label::before{content:"";width:6px;height:6px;border-radius:50%;background:#fff}
.feed-sub{font-family:var(--nyf-font-sans);font-size:14px;line-height:1.3;color:var(--nyf-grey-dark);margin:var(--nyf-space-1) 0 0}
.feed-close{display:none;font:400 22px/1 var(--nyf-font-sans);width:44px;height:44px;border:0;border-radius:999px;background:var(--nyf-cream);color:var(--nyf-ink);cursor:pointer}
.feed-empty{color:var(--nyf-grey-dark);font-size:18px;margin:0}
/* On every screen (Kyle), a floating "Live updates" button, bottom right, opens the feed over the page: a 380px panel
   from the right, the whole screen on a phone. Escape, the close button or a tap outside it closes it. */
.feed-host.has-feed>.feed-fab{display:inline-flex}
.feed-fab[hidden]{display:none!important}
.feed-fab{position:fixed;right:max(16px,env(safe-area-inset-right));bottom:max(16px,env(safe-area-inset-bottom));z-index:900;align-items:center;gap:var(--nyf-space-1);
    font:inherit;font-family:var(--nyf-font-headline);text-transform:uppercase;font-size:18px;line-height:1;background:var(--nyf-ink);color:#fff;border:0;border-radius:999px;
    padding:var(--nyf-space-2) var(--nyf-space-3);box-shadow:0 4px 16px rgb(0 0 0 / 25%);cursor:pointer}
.feed-fab:focus-visible{outline:3px solid var(--nyf-yellow);outline-offset:2px}
.fab-dot{width:10px;height:10px;border-radius:50%;background:var(--nyf-red);animation:fab-pulse 2s ease-in-out infinite}
/* The LIVE flag, the button's dot and its "Live" only while the feed is collecting (feed.js sets .feed-live; Kyle) */
.feed-host:not(.feed-live) :is(.live-label,.fab-dot,.fab-live){display:none}
.fab-count:not(:empty){font-family:var(--nyf-font-sans);text-transform:none;font-size:15px;background:var(--nyf-yellow);color:var(--nyf-ink);border-radius:999px;padding:2px var(--nyf-space-1)}
.feed-host.has-feed>.feed-panel{display:block;position:fixed;top:0;right:0;bottom:0;z-index:1000;width:min(380px,100%);box-sizing:border-box;background:#fff;
    overflow-y:auto;overscroll-behavior:contain;padding:0 var(--nyf-gutter) var(--nyf-space-6);box-shadow:-4px 0 24px rgb(0 0 0 / 20%);
    transform:translateX(100%);visibility:hidden;transition:transform .25s ease,visibility 0s linear .25s}
html.feed-open .feed-host.has-feed>.feed-panel{transform:none;visibility:visible;transition:transform .25s ease}
.feed-close{display:inline-block}
html.feed-open .feed-host.has-feed>.feed-backdrop:not([hidden]){display:block;position:fixed;inset:0;z-index:999;background:rgb(0 0 0 / 40%)}
html.feed-open{overflow:hidden}
@media (max-width:599px){.feed-host.has-feed>.feed-panel{width:100%;box-shadow:none}}
@media (prefers-reduced-motion:reduce){.fab-dot{animation:none}.feed-host.has-feed>.feed-panel{transition:none}}
@keyframes fab-pulse{0%,100%{opacity:1}50%{opacity:.35}}
/* The feed as a live blog (Kyle, 2026-10-30): each post opens with its time, then the byline; the text in Chronicle,
   the site's article serif; the platforms at the foot. Labels in Knockout 32. */
.feed-caught-up{display:flex;align-items:center;gap:var(--nyf-space-2);margin:var(--nyf-space-3) 0 0;font-family:var(--nyf-font-sans);font-size:13px;text-transform:uppercase;letter-spacing:.06em;color:var(--nyf-grey)}
.feed-caught-up::before,.feed-caught-up::after{content:"";flex:1;border-top:1px solid var(--rule)}
/* The post just above the line drops its own rule, which stacked on the line's (Kyle, 2026-11-02); the line then sits
   as far below that post as the next post sits below it. */
.post:has(+ .feed-caught-up){border-bottom:0}.post + .feed-caught-up{margin-top:0}
.feed-new{position:sticky;top:96px;z-index:2;display:block;margin:var(--nyf-space-1) auto;font:inherit;font-family:var(--nyf-font-sans);font-size:15px;background:var(--nyf-ink);color:#fff;border:0;border-radius:999px;padding:var(--nyf-space-1) var(--nyf-space-2);cursor:pointer}
.feed-more,.thread-more{font:inherit;font-family:var(--nyf-font-sans);font-size:15px;background:none;border:1px solid var(--nyf-ink);color:var(--nyf-ink);padding:var(--nyf-space-1) var(--nyf-space-2);cursor:pointer;margin-top:var(--nyf-space-3)}
.post{padding:var(--nyf-space-3) 0;border-bottom:1px solid var(--rule)}
.post-time{display:flex;align-items:baseline;gap:var(--nyf-space-1);font-family:var(--nyf-font-sans);font-size:14px;line-height:1}
.post-time a{color:var(--nyf-red);text-decoration:none;text-transform:uppercase;letter-spacing:.04em}
.post-time a:hover{text-decoration:underline}
.post-ago{color:var(--nyf-grey)}
/* The pinned post: shaded the brand's cream to the panel's edges, under a pin and "Pinned" (Kyle, 2026-11-04). */
.post.is-pinned{background:var(--nyf-cream);margin:0 calc(-1 * var(--nyf-gutter));padding:var(--nyf-space-2) var(--nyf-gutter) var(--nyf-space-3);border-bottom:0}
.post-pinned{display:flex;align-items:center;gap:6px;font-family:var(--nyf-font-sans);font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--nyf-ink);margin:0 0 var(--nyf-space-1)}
/* A preview link's hidden post (Kyle, 2026-11-08): marked so it can't be mistaken for one readers saw */
.post-hidden{font-family:var(--nyf-font-sans);font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--nyf-party-rep, #b3261e);margin:0 0 var(--nyf-space-1)}
.post-pinned svg{flex:none;transform:rotate(30deg)}
.post.is-pinned .post-card{background:#fff}
.post-shared{font-family:var(--nyf-font-sans);font-size:14px;color:var(--nyf-grey-dark);margin:6px 0 0}
.post-by{display:flex;align-items:center;gap:var(--nyf-space-1);margin:10px 0 0;font-family:var(--nyf-font-sans);font-size:15px;font-weight:700}
.avatar{width:28px;height:28px;border-radius:50%;flex:none;background:var(--nyf-cream);object-fit:cover}
.post-text{font-family:var(--nyf-font-serif);font-size:17px;line-height:1.55;margin:10px 0 0;white-space:pre-line;overflow-wrap:anywhere}
.post-text a{color:var(--nyf-blue)}
.post-foot{margin:var(--nyf-space-2) 0 0;font-family:var(--nyf-font-sans);font-size:13px;color:var(--nyf-grey)}
.post-foot a{color:var(--nyf-grey);text-decoration:none;border-bottom:1px solid var(--rule)}
.post-foot a:hover{color:var(--nyf-ink);border-color:currentColor}
.post-foot .sep{margin:0 var(--nyf-space-1)}
/* A reporter's thread: one post, the later replies as updates */
.post-update{margin-top:var(--nyf-space-2);padding-top:var(--nyf-space-2);border-top:1px dashed var(--rule)}
.update-time{font-family:var(--nyf-font-sans);font-size:13px;text-transform:uppercase;letter-spacing:.04em;color:var(--nyf-grey);margin:0}
.thread-more{margin:var(--nyf-space-2) 0 0}
.post-media{display:grid;gap:2px;margin-top:var(--nyf-space-2);overflow:hidden}
/* Media (Kyle's feed code): one item full width, keeping its shape; two to four in a 16:9 grid, the first of three
   spanning two rows */
.post-media.n2,.post-media.n3,.post-media.n4{grid-template-columns:1fr 1fr;aspect-ratio:16/9}
.post-media.n3>:first-child{grid-row:span 2}
.post-media .photo{display:block;min-height:0;cursor:zoom-in;background:var(--nyf-cream)}
.post-media img,.post-media video{display:block;width:100%;height:100%;object-fit:cover;background:var(--nyf-cream)}
.post-media.n1 img,.post-media.n1 video{max-height:510px;object-fit:contain}
.post-media video{background:#000}
.gif-box{position:relative;display:block;max-height:510px;background:var(--nyf-cream)}
.gif-box .gif{display:block;width:100%;height:100%;object-fit:contain}
.gif-tag{position:absolute;left:8px;bottom:8px;padding:1px 5px;border-radius:4px;background:rgb(0 0 0 / 70%);color:#fff;font-size:11px;font-weight:700}
/* A video that won't play: its poster, dimmed, with a link to watch it on the platform */
.video-fallback{position:relative;display:block;min-height:120px;background:#000}
.video-fallback img{opacity:.6}
.video-fallback span{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700}
/* A link: a compact story box (a thumbnail, the source, the headline), a yellow rule at its left */
.post-card{display:flex;min-width:0;overflow:hidden;gap:var(--nyf-space-2);margin-top:var(--nyf-space-2);padding:12px;background:#faf8f4;border-left:3px solid var(--nyf-yellow);color:inherit;text-decoration:none}
.post-card img{width:96px;height:64px;flex:none;object-fit:cover;background:var(--nyf-cream)}
.card-text{display:flex;flex-direction:column;gap:3px;min-width:0}
.card-host{font-family:var(--nyf-font-sans);font-size:12px;text-transform:uppercase;letter-spacing:.06em;color:var(--nyf-grey);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.post-card .card-title{font-family:var(--nyf-font-sans);text-transform:none;font-size:15px;line-height:1.25;margin:0;font-weight:700;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}
.post-card:hover .card-title{text-decoration:underline}
/* A quoted post: a pull quote, a grey rule at its left */
.post-quote{margin-top:var(--nyf-space-2);padding:2px 0 2px 14px;border-left:3px solid var(--rule)}
.post-quote.missing{font-family:var(--nyf-font-sans);color:var(--nyf-grey-dark);font-size:15px}
.quote-link{display:block;color:inherit;text-decoration:none}
.quote-link:hover .quote-text{color:var(--nyf-ink)}
.quote-by{display:block;font-family:var(--nyf-font-sans);font-size:14px;font-weight:700}
.quote-text{display:block;font-family:var(--nyf-font-serif);font-size:15px;line-height:1.5;color:var(--nyf-grey-dark);margin-top:var(--nyf-space-half);white-space:pre-line;overflow-wrap:anywhere}
.post-quote .post-media,.post-quote .post-card{margin-top:var(--nyf-space-1)}
/* A thread: the author's replies under the first post, joined by a line */
.thread-more{margin:var(--nyf-space-2) 0 0}
/* The photo lightbox (Kyle's feed code) */
html.lb-open{overflow:hidden}
.lightbox{width:100vw;height:100dvh;max-width:none;max-height:none;margin:0;padding:0;border:0;background:rgb(0 0 0 / 96%);color:#fff;overscroll-behavior:contain}
.lightbox::backdrop{background:transparent}
.lightbox[open]{display:grid;place-items:center}
.lb-img{max-width:100vw;max-height:100dvh;object-fit:contain;user-select:none;-webkit-user-select:none}
.lb-btn{position:absolute;display:grid;place-items:center;width:44px;height:44px;padding:0;border:0;border-radius:999px;background:rgb(0 0 0 / 55%);color:#fff;font:400 28px/1 var(--nyf-font-sans);cursor:pointer}
.lb-btn:hover{background:rgb(60 60 60 / 75%)}.lb-btn[hidden]{display:none}
.lb-close{top:max(12px,env(safe-area-inset-top));left:12px;font-size:20px}
.lb-prev{left:12px;top:50%;transform:translateY(-50%)}.lb-next{right:12px;top:50%;transform:translateY(-50%)}
.lb-count{position:absolute;top:max(12px,env(safe-area-inset-top));right:16px;margin:0;line-height:44px;font-family:var(--nyf-font-sans);font-size:14px;font-weight:700}
.lb-alt{position:absolute;left:0;right:0;bottom:0;margin:0;padding:12px 16px max(12px,env(safe-area-inset-bottom));background:linear-gradient(transparent,rgb(0 0 0 / 70%));font-family:var(--nyf-font-sans);font-size:14px;text-align:center}
.lb-alt[hidden]{display:none}
/* Races in a section sit 48px apart, a rule midway (generous between groups, tight inside: Decisions) */
.home-race{border-top:1px solid var(--rule);padding-top:var(--nyf-space-3);margin-bottom:var(--nyf-space-3)}
.home-race:first-of-type{border-top:0;padding-top:0}
.home-race h2,.home-race h3{margin:0 0 var(--nyf-space-1)}.home-race h3{font-family:var(--nyf-font-headline);font-weight:400;text-transform:uppercase;font-size:24px}
.home-race h3 a,.home-race h2 a{color:inherit;text-decoration:none}
/* The Supreme Court section (Kyle): justices elected beside the map, in two equal columns */
.chamber-row{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:var(--nyf-space-5);align-items:start;margin:0 0 var(--nyf-space-6)}
@media (max-width:860px){.chamber-row{grid-template-columns:minmax(0,1fr)}.chamber-row .race-map{margin-top:var(--nyf-space-2)}}
.home figcaption{display:none}
/* The court map: districts with races yellow, the others pale; county lines faint; the districts' borders dark; each
   district's number */
.court-map path.land{fill:var(--none);cursor:default}
.court-map path.court{fill:var(--nyf-yellow);cursor:pointer}
.court-map .county-lines{fill:none;stroke:#fff;stroke-opacity:.7;stroke-width:.75;pointer-events:none}
.court-map .edges path{stroke:var(--nyf-ink);stroke-width:1.25}
.court-map .labels text{font-family:var(--nyf-font-sans);fill:var(--nyf-ink);text-anchor:middle;dominant-baseline:middle;paint-order:stroke;stroke:#fff;stroke-width:3px;stroke-linejoin:round;pointer-events:none}
.map-legend i.court{background:var(--nyf-yellow)}
/* Section headers are nysfocus.com's: a yellow bar the width of the page's container (12px above and below the label,
   the site's py-3), the label in line with the text; sections --nyf-section apart, 16px (48px from 768px) to the first
   thing in them */
h2.section{font-size:24px;line-height:1;background:var(--nyf-yellow);padding:12px var(--nyf-gutter);margin:var(--nyf-section) calc(-1 * var(--nyf-gutter)) var(--nyf-space-2)}
/* As on nysfocus.com: 30px on a 36px line from 768px, so the bar is 60px tall (48px on a phone) */
@media (min-width:768px){h2.section{font-size:30px;line-height:36px;margin-bottom:var(--nyf-space-6)}}
/* A section's description, under its bar (Kyle) */
.section-dek{font-family:var(--nyf-font-sans);font-size:18px;line-height:1.4;color:var(--nyf-grey-dark);max-width:43rem;margin:0 0 var(--nyf-space-4)}
h2.section:has(+ .section-dek){margin-bottom:var(--nyf-space-2)}
@media (min-width:768px){.section-dek{margin-bottom:var(--nyf-space-6)}}
h2.section+.note{margin-top:0}
.more{font-size:16px;margin:var(--nyf-space-2) 0 0}.note{font-size:16px;color:var(--nyf-grey-dark)}
/* Balance of power: seats won by party, not yet called in the middle, a line at the majority */
.balance h3{font-family:var(--nyf-font-headline);font-weight:400;text-transform:uppercase;font-size:24px;margin:0 0 var(--nyf-space-1)}
.balance h3 a{color:inherit;text-decoration:none}
.balance-bar{position:relative;display:flex;height:28px;background:var(--none)}
.balance-bar span{display:block;height:100%;transition:width .4s}
.b-dem{background:var(--dem)}.b-rep{background:var(--rep)}.b-oth{background:var(--oth)}.b-none{background:var(--none)}
.b-majority{position:absolute;top:-6px;bottom:-6px;width:2px;background:var(--nyf-ink);transform:translateX(-1px)}
.balance-key{display:flex;flex-wrap:wrap;gap:var(--nyf-space-half) var(--nyf-space-2);font-size:16px;margin:var(--nyf-space-1) 0 0}
.balance-key b{font-weight:700}.swatch.none{background:var(--none);border:1px solid var(--rule)}
.b-need{color:var(--nyf-grey-dark)}
.all-races{list-style:none;padding:0;columns:2;font-size:16px}.all-races li{margin:var(--nyf-space-half) 0}
/* Home races: table and map side by side, half and half; the state and the city maps side by side; no captions (one
   note at the top of the page says what the colors mean) */
.race-layout.home{grid-template-columns:minmax(0,1fr) minmax(0,1fr);grid-template-areas:"table map";column-gap:var(--nyf-space-5)}
.race-layout.home.stacked{grid-template-columns:minmax(0,1fr);grid-template-areas:"table" "map"}.race-layout.home.stacked .race-map{margin-top:var(--nyf-space-2)}
@media (max-width:860px){.race-layout.home{grid-template-columns:minmax(0,1fr);grid-template-areas:"table" "map"}.race-layout.home .race-map{margin-top:var(--nyf-space-2)}}
.race-layout.home figcaption{display:none}
/* The Statewide section: the three races' tables, side by side from 1000px, one above the other narrower; their maps
   are in "At a glance" at the top (Kyle, 2026-11-03). */
@media (min-width:1000px){.sw-tables{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));column-gap:var(--nyf-space-5);align-items:start}
.sw-tables .home-race{border-top:0;padding-top:0;margin-bottom:0}}
@media (min-width:1280px){.sw-tables{column-gap:var(--nyf-space-8)}}
/* No maps on the home page on a phone (Kyle): they made it 60% longer. The tables, seats won and "Detailed results"
   stay; every race page has its map. The notes about the maps go with them: the map colors' footnote and the court's
   note, whose numbers the section's description already gives */
@media (max-width:599px){.home-results .race-map,.home-results .footnote,.home-results .chamber-row .note{display:none}}
/* One map at a time (Kyle): a "New York State / New York City" switch above it */
.maps.switchable{display:block}.maps.switchable>svg,.maps.switchable .city{width:100%}
/* Both views the same height, so switching doesn't move the page: the city fits in the state's frame */
.maps.switchable .results-map{aspect-ratio:600/440;height:auto}
.maps.switchable .city[hidden],.maps.switchable>svg[hidden]{display:none}
.map-switch{margin:0 0 var(--nyf-space-1)}
/* "Shaded / Circles" (Kyle, 2026-11-05; every map of counties), under the "New York State / New York City" switch on every screen, both starting at the left. In
   circles, the counties go pale under circles sized by their ballots; the size key under the legend, its circles at
   their size on the screen (cqw: the figure's width, which the maps fill). */
.map-switches{display:flex;flex-direction:column;align-items:flex-start}
.race-map:has(.mode-switch){container-type:inline-size}
.results-map .bubbles{display:none}
.race-map.circles .results-map .bubbles{display:inline}
.race-map.circles .results-map .areas path{fill:var(--none)}
.results-map .bubbles circle{fill-opacity:.88;stroke:#fff;stroke-width:1;vector-effect:non-scaling-stroke;cursor:pointer}
.results-map .bubbles circle:hover{stroke:var(--nyf-ink);stroke-width:2}
.size-key{display:none;flex-wrap:wrap;align-items:center;gap:var(--nyf-space-half) var(--nyf-space-2);font-family:var(--nyf-font-sans);font-size:14px;color:var(--nyf-grey);margin-top:var(--nyf-space-1)}
.size-key .key{display:inline-flex;align-items:center;gap:var(--nyf-space-half)}
.size-key svg{height:auto;flex:none}
.size-key circle{fill:none;stroke:var(--nyf-grey-dark);stroke-width:1}
/* The size key beside the legend, on one line where there's room, on every screen (Kyle, 2026-11-05) */
.legend-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--nyf-space-1) var(--nyf-space-3);margin:var(--nyf-space-2) 0 var(--nyf-space-half)}
.legend-row>.map-legend,.legend-row>.size-key{margin:0}
/* Labels under their swatches and circles (Kyle, 2026-11-05), so the two fit side by side; the labels line up along
   the bottom */
.map-legend .sw{display:inline-flex}
.legend-row{align-items:flex-end}
.legend-row>.map-legend{align-items:flex-end}
.legend-row>.map-legend .key{flex-direction:column;align-items:flex-start;gap:var(--nyf-space-half)}
.legend-row>.size-key{align-items:flex-end}
.legend-row>.size-key .key{flex-direction:column;gap:var(--nyf-space-half)}
.race-map.circles .size-key:not([data-view]),.race-map.circles:not([data-view="city"]) .size-key[data-view="state"],.race-map.circles[data-view="city"] .size-key[data-view="city"]{display:flex}
/* The map's "New York State / New York City" switch, quieter than the table's "Combined / By Party" (Kyle, 2026-11-03:
   it stood out above the maps once the sections lost their yellow bar): 14px, a light border, the picked view in ink on
   a pale ground rather than white on ink. */
.map-switch.view-toggle{border-color:var(--rule)}
.map-switch.view-toggle button{font-size:14px;color:var(--nyf-grey-dark);padding:2px var(--nyf-space-1)}
.map-switch.view-toggle button+button{border-left:1px solid var(--rule)}
.map-switch.view-toggle button[aria-pressed="true"]{background:var(--none);color:var(--nyf-ink)}
.map-switch.view-toggle button:hover{color:var(--nyf-ink)}
/* A page's footnote sits with the source line, under one rule. The home page's source line has its own section gap and
   rule, as on every page (Kyle, 2026-11-03: it sat 4px under the last map's legend). */
.source.footnote+.source{border-top:0;margin-top:var(--nyf-space-half);padding-top:0}


/* Early voting turnout (Kyle, 2026-11-02): one color in five steps, not a party's, since it isn't a result. On a phone
   the map comes before the county table. */
.ev-1{fill:#fcebc0;background:#fcebc0}.ev-2{fill:#f8cf7a;background:#f8cf7a}.ev-3{fill:#eeaa3c;background:#eeaa3c}
.ev-4{fill:#c97f1a;background:#c97f1a}.ev-5{fill:#8f5512;background:#8f5512}
/* The turnout page's counties before their ballots come in (Kyle, 2026-11-05) */
.ev-0{fill:var(--nyf-party-none);background:var(--nyf-party-none)}
/* Turnout (Kyle, 2026-11-05): a county still counting, its row shaded in cream with its Reporting in ink, and its map
   shape hatched; the note under the table and the legend's key only while one is (hidden, so nothing moves). The
   unofficial-count note under the statewide figure. */
/* A county still counting: light diagonal stripes over the cream band, as its map shape is hatched ("in progress";
   Kyle, 2026-11-05), painted on the row so they run on across its cells. */
.tv-table tr.tv-counting{background:repeating-linear-gradient(135deg,rgb(12 35 41/.07) 0 1.5px,transparent 1.5px 6px),var(--nyf-cream)}
.tv-table tr.tv-counting>*{background:transparent}   /* the county name's cell too (white where a phone pins it) */
.tv-name{position:relative;cursor:help;text-decoration:underline dotted;text-decoration-color:var(--nyf-grey);text-underline-offset:3px;outline-offset:2px}
.tv-key-partial[data-none]{visibility:hidden}
.tv-hatch{background:repeating-linear-gradient(45deg,rgb(12 35 41/.55) 0 1.5px,transparent 1.5px 4px)!important;border:1px solid var(--nyf-grey-light)}
.tv-caveat{max-width:640px;margin:var(--nyf-space-2) 0 0;padding:var(--nyf-space-1) var(--nyf-space-2);border-left:3px solid var(--nyf-yellow);background:var(--nyf-cream);font-size:var(--nyf-text-small);line-height:1.45;color:var(--nyf-ink)}
.tv-glance{margin:0 0 var(--nyf-section)}
.turnout-table abbr{text-decoration:none}
.race-layout.turnout{grid-template-areas:"table map";grid-template-rows:auto}
@media (max-width:860px){.race-layout.turnout{grid-template-areas:"map" "table"}.race-layout.turnout .race-map{margin:0 0 var(--nyf-section)}}
.turnout-table .ev-bar{display:inline-block;width:64px;height:10px;margin-right:var(--nyf-space-1);background:var(--rule);vertical-align:baseline}
.turnout-table .ev-bar i{display:block;height:100%}
.turnout-table tfoot th,.turnout-table tfoot td{font-weight:700;border-top:2px solid var(--nyf-ink);border-bottom:0}
@media (max-width:599px){.turnout-table .ev-bar{display:none}}
.ev-big{font-family:var(--nyf-font-sans);font-size:20px;line-height:1.3;margin:0 0 var(--nyf-space-1)}
.ev-big strong{display:block;font-family:var(--nyf-font-headline);font-size:48px;line-height:1}
.ev-sub{font-size:14px;color:var(--nyf-grey);margin:0 0 var(--nyf-space-2)}
.map-tip .tip-big{display:block;font-family:var(--nyf-font-headline);font-size:24px;line-height:1.1;margin:var(--nyf-space-half) 0}
.turnout-table .ev-pct{display:inline-block;min-width:3.4em}
@media (min-width:861px){.race-layout.turnout .race-map{position:sticky;top:76px}}
@media (max-width:599px){.turnout-table{font-size:15px}.turnout-table thead th{white-space:normal;vertical-align:bottom}.turnout-table .ev-pct{min-width:0}}
/* "At a glance" before and after the polls close (Kyle, 2026-11-03): early voting until 9 p.m. ET, then the results
   (.polls-closed, set by the page's head script, and by results.js at 9). */
:root:not(.polls-closed) .post-polls,.polls-closed .pre-polls{display:none}
.ev-glance{margin-top:var(--nyf-section)}
/* The section bar's own margin alone sets the gap between the home page's sections (--nyf-section, as decided): the
   last margin inside each section goes. Without it, a section ending in a 48px margin stood 48px from the next on a
   phone, not 32px. */
.home-results>section>:last-child{margin-bottom:0}
/* The statewide races open with the standard section bar under "At a glance" (Kyle, 2026-11-03): its bar's own top
   margin, a section gap, sets the space under it. Section headings that open a page of their own (US House) link to
   it, styled as the heading. */
.home-section>h2.section a{color:inherit;text-decoration:none}
/* "At a glance" (Kyle, 2026-11-03): the home page's top. On the left, the headline and subheading, then the statewide
   tabs and the race's results table; on the right, the race's map. Then, full width, the US House as 26 circles in one
   row, and the State Senate and State Assembly side by side. Under 861px, one column: the headline, the tabs and table,
   then the map. On a phone, the circles in rows of ten. */
.g-top{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:var(--nyf-space-5);align-items:start}
@media (min-width:1280px){.g-top{column-gap:var(--nyf-space-8)}}
@media (max-width:860px){.g-top{grid-template-columns:minmax(0,1fr)}.glance-map{margin-top:var(--nyf-section)}}
.g-top .dek{margin-bottom:0}
.glance{margin-top:var(--nyf-section)}
/* Five tabs (Kyle, 2026-11-03: the statewide races, NY-17 and NY-21): where they don't fit, the row scrolls sideways. */
.sw-tabs{display:flex;gap:var(--nyf-space-3);border-bottom:1px solid var(--rule);margin:0;overflow-x:auto;scrollbar-width:none}
.sw-tabs::-webkit-scrollbar{display:none}
.sw-tabs button{flex:none}
.sw-tabs button{font:inherit;font-family:var(--nyf-font-sans);font-size:16px;background:none;border:0;border-bottom:3px solid transparent;margin-bottom:-1px;padding:6px 0;cursor:pointer;color:var(--nyf-grey-dark);white-space:nowrap}
.sw-tabs button[aria-selected="true"]{color:var(--nyf-ink);border-bottom-color:var(--nyf-ink);font-weight:600}
.sw-tabs button:hover{color:var(--nyf-ink)}
.glance-map .race-map figcaption{display:none}
/* Key Races' maps are one size whichever tile is picked (Kyle, 2026-11-04): a House district's map takes the statewide
   map's shape (450 by 330) and sits where it does, under the room its "New York State / New York City" switch takes
   (22px and an 8px gap), so the legend under each is in the same place. */
.glance-map .sw-map[data-sw-map^="congress"] .race-map>svg.results-map{width:100%;height:auto;aspect-ratio:450/330;margin-top:30px}
/* That room is the switch's: 22px exactly in every browser (a 16px line, 2px above and below, a 1px border), not the
   font's own line height, which Safari sets a pixel or two taller than Chrome. */
.glance-map .map-switch.view-toggle{box-sizing:border-box;height:22px}
.glance-map .map-switch.view-toggle button{line-height:16px}
/* The statewide race, tight, as the boxes were (Kyle, 2026-11-03): a line per candidate (party dot, name, share), by
   votes; the winner marked by the ✓; nothing bold (Knockout 32 has one weight, so bold is faked); then the reporting
   line.
   The tabs' rule is the list's top rule. */
.glance-below{margin-top:var(--nyf-section);border-top:1px solid var(--rule);padding-top:var(--nyf-space-3);font-family:var(--nyf-font-sans)}
.glance-below .g-row{border:0;padding:0}
.g-pair{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:var(--nyf-space-8);margin-top:var(--nyf-space-3);padding-top:var(--nyf-space-3);border-top:1px solid var(--rule)}
@media (max-width:860px){.g-pair{grid-template-columns:minmax(0,1fr);row-gap:var(--nyf-space-3)}}
.glance{font-family:var(--nyf-font-sans)}
.g-row{padding:var(--nyf-space-2) 0;border-bottom:1px solid var(--rule)}.g-row:first-child{padding-top:0}.g-row:last-child{border-bottom:0;padding-bottom:0}
.g-head{display:flex;justify-content:space-between;align-items:baseline;gap:8px;margin-bottom:8px}
.g-head h2{margin:0;font-size:16px;line-height:1.2}.g-head h2 a{color:var(--nyf-ink);text-decoration:none}
.g-head h2 a:hover{text-decoration:underline;text-decoration-color:var(--nyf-yellow);text-decoration-thickness:3px}
.g-head span{font-size:14px;color:var(--nyf-grey-dark)}.g-head .d,.g-key .d{color:var(--dem);font-weight:600}.g-head .r,.g-key .r{color:var(--rep);font-weight:600}
.g-house{position:relative}
.g-dots{display:grid;grid-template-columns:repeat(26,minmax(0,1fr));gap:6px}
.hd{aspect-ratio:1;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:13px;font-weight:600;letter-spacing:-.01em;text-decoration:none;color:#fff;background:var(--oth)}
.hd.dem{background:var(--dem)}.hd.rep{background:var(--rep)}.hd.wor{background:var(--wor)}.hd.con{background:var(--con)}
.hd.none{background:var(--none);color:var(--nyf-grey-dark)}.hd:hover,.hd:focus-visible{outline:2px solid var(--nyf-ink);outline-offset:1px}
/* The district's number alone (Kyle, 2026-11-03), in one row of 26; "NY-17" stays its label and its card's name. On a
   phone, rows of ten. */
@media (max-width:600px){.g-dots{grid-template-columns:repeat(10,minmax(0,1fr));gap:5px}}
.g-bar{position:relative;display:flex;height:16px;background:var(--none)}.g-bar i{display:block;height:100%}
.g-bar .dem{background:var(--dem)}.g-bar .rep{background:var(--rep)}.g-bar .oth{background:var(--oth)}.g-bar .none{background:var(--none)}
.g-bar b{position:absolute;top:-4px;bottom:-4px;width:2px;background:var(--nyf-ink);transform:translateX(-1px)}
.g-key{display:flex;justify-content:space-between;gap:8px;margin:6px 0 0;font-size:14px;color:var(--nyf-grey-dark)}
/* Seats flipped (Kyle, 2026-11-05), on the chamber pages: "D flip" under the district, in the color of the party that
   gained the seat. */
.districts .flip{display:block;font-size:var(--nyf-text-caps);text-transform:uppercase;letter-spacing:.04em;font-weight:600;color:var(--nyf-grey-dark)}
.districts .flip:empty{display:none}.districts .flip.d{color:var(--dem)}.districts .flip.r{color:var(--rep)}
/* Layout shift as the fonts load (2026-11-02): pages draw first in a stand-in font, whose own line spacing made table
   rows and the kicker a pixel or two taller than in Knockout, which the page then shrank to; over 62 rows that moved
   everything below, and the breadcrumbs sat on a line of the stand-in font's height. These lines are set to the
   heights Knockout gives them (within a pixel), so little moves when it arrives. Headlines and other text still wrap
   differently in the two fonts; that's the font kit's to fix (font metric overrides), not a page's. */
.kicker{line-height:16px}
.crumbs{vertical-align:top}
.map-legend,.race-map figcaption{line-height:16px}
.results th,.results td,.county-table th,.county-table td{line-height:19px}
.results .lines{line-height:16px}
.county-table td small{line-height:15px}
.county-table thead th,.county-table thead button{line-height:15px}
/* The early voting table's columns at fixed widths: sized to their text, they moved sideways when the fonts arrived. */
.turnout-table{table-layout:fixed}
/* The turnout table's five columns (a Reporting column, 2026-11-05). */
/* Its widths on its columns. */
.tv-table col:nth-child(1){width:28%}.tv-table col:nth-child(2){width:20%}.tv-table col:nth-child(3){width:22%}.tv-table col:nth-child(4){width:30%}
.turnout-table thead th:nth-child(1){width:28%}.turnout-table thead th:nth-child(2){width:20%}
.turnout-table thead th:nth-child(3){width:22%}.turnout-table thead th:nth-child(4){width:30%}
@media (max-width:599px){.turnout-table thead th:nth-child(1){width:30%}.turnout-table thead th:nth-child(2){width:23%}.turnout-table thead th:nth-child(3){width:21%}.turnout-table thead th:nth-child(4){width:26%}}
/* The narrowest phones (under 400px): smaller type and tighter cells, so every county and number fits its column. */
@media (max-width:399px){.turnout-table{font-size:13px}.turnout-table th,.turnout-table td{padding-left:2px;padding-right:2px}
.turnout-table thead th:nth-child(1){width:29%}.turnout-table thead th:nth-child(2){width:22%}.turnout-table thead th:nth-child(3){width:22%}.turnout-table thead th:nth-child(4){width:27%}}
@media (max-width:359px){.turnout-table{table-layout:auto}}
@media (max-width:599px){.tv-table col:nth-child(1){width:30%}.tv-table col:nth-child(2){width:23%}.tv-table col:nth-child(3){width:21%}.tv-table col:nth-child(4){width:26%}}
@media (max-width:399px){.turnout-table thead th{font-size:12px}.tv-table tfoot{font-size:13px}.tv-table col:nth-child(1){width:29%}.tv-table col:nth-child(2){width:22%}.tv-table col:nth-child(3){width:22%}.tv-table col:nth-child(4){width:27%}}
/* Phones (Kyle, 2026-11-02): no page wider than the screen. The county table, a column per candidate, scrolls left and
   right in its own box, the county names pinned at the left; the district lists put each candidate on a line of their
   own in the results column. */
.county-list{overflow-x:auto;-webkit-overflow-scrolling:touch}
@media (max-width:599px){
  .county-table thead th:first-child,.county-table tbody th{position:sticky;left:0;z-index:1;background:#fff}
  .county-table tbody th{box-shadow:1px 0 0 var(--rule)}
  .districts thead th,.districts tr[data-row^="supreme-court"] th{white-space:normal}
}
.nowrap{white-space:nowrap}
@media (max-width:359px){.districts{font-size:14px}.districts th,.districts td{padding-left:2px;padding-right:2px}}
/* The district lists stack their candidates, a line each (Kyle, 2026-11-02): the winners once called, the shares
   until then. */
.districts .share,.districts .winner,.districts .cand{display:block;margin-right:0;white-space:nowrap}
@media (max-width:599px){.districts .share,.districts .winner,.districts .cand{white-space:normal}}
.districts .unopposed{color:var(--nyf-grey-dark);font-size:14px}
/* The district lists: full names, last names only on a phone (Kyle, 2026-11-02). */
.districts .name-last{display:none}
@media (max-width:599px){.districts .inc-wide{display:none}.districts .name-full{display:none}.districts .name-last{display:inline}.districts .nm::before{content:attr(data-last)}}
/* The home page (Kyle, 2026-11-03): under the full-width headline and subheading, early voting until 9 p.m., then "Key
   Races" (the races in brief and their map) and the House and the Legislature at a glance; each section opens with its
   heading, description and links on the left and its map on the right, then its races three to a row. */
.ev-row .ev-glance{margin-top:0}
.ev-row{margin-bottom:var(--nyf-section)}
.sec-top{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);column-gap:var(--nyf-space-5);align-items:start;margin-bottom:var(--nyf-section)}
@media (min-width:1280px){.sec-top{column-gap:var(--nyf-space-8)}}
@media (max-width:860px){.sec-top{grid-template-columns:minmax(0,1fr)}.sec-map{margin-top:var(--nyf-space-3)}}
.sec-top .section-dek{margin-bottom:var(--nyf-space-2)}
.sec-top .race-map{margin:0}
.sec-links{display:flex;flex-wrap:wrap;gap:var(--nyf-space-1) var(--nyf-space-3);margin:0}
.sec-map .sw-tabs{margin-bottom:var(--nyf-space-2)}
.home-section .sw-tables{row-gap:var(--nyf-space-6)}
@media (max-width:599px){.sec-map .sw-tabs{display:none}}
/* The races to watch keep one height whichever races are picked (Kyle): room for the top two candidates (Kyle), a reporting line
   that wraps and the AP's call, with "Detailed results" at the foot, so a new pick doesn't move the page. */
[data-watch] .race-table{display:flex;flex-direction:column;min-height:15.75rem}
[data-watch] .race-table .more{margin-top:auto}
@media (max-width:599px){[data-watch] .race-table{min-height:17.5rem}}
@media (min-width:861px){.sec-side,.ev-row .g-main{align-self:center}}
/* The home page's sections without the yellow bar (Kyle, 2026-11-03): the heading over the description in the left
   column, centered against the map, and a thin yellow rule between sections. */
.home-results .home-section{border-top:2px solid var(--nyf-yellow);padding-top:var(--nyf-section);margin-top:var(--nyf-section)}
.sec-title{font-family:var(--nyf-font-headline);font-weight:400;text-transform:uppercase;font-size:24px;line-height:1.05;margin:0 0 var(--nyf-space-2)}
@media (min-width:768px){.sec-title{font-size:32px}}
.sec-title a{color:inherit;text-decoration:none}.sec-title a:hover{text-decoration:underline;text-decoration-color:var(--nyf-yellow)}
.glance .section-dek{margin-bottom:var(--nyf-space-3)}
/* "Key Races"' tiles (Kyle, 2026-11-03, in place of tabs over a table): three in a row, a border around each and no
   color bar over the top; the picked one's border in ink; each picks its race's map. One under another on a phone. */
.kr-tiles{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--nyf-space-1);border:0;overflow:visible}
@media (max-width:599px){.kr-tiles{grid-template-columns:minmax(0,1fr)}}
.kr-tile{display:flex;flex-direction:column;border:1px solid var(--rule);padding:10px 12px;background:#fff;cursor:pointer;font-family:var(--nyf-font-sans);color:var(--nyf-ink)}
.kr-tile:hover{border-color:var(--nyf-grey)}
.kr-tile[aria-selected="true"]{border-color:var(--nyf-grey-dark);box-shadow:inset 0 0 0 1px var(--nyf-grey-dark)}
.kr-tile h3{margin:0 0 6px;font-family:var(--nyf-font-headline);font-weight:400;text-transform:uppercase;font-size:14px;letter-spacing:.02em;line-height:1.05;white-space:nowrap}
.kr-tile .g-race{flex:1;display:flex;flex-direction:column}
.kr-tile ul{flex:1;list-style:none;margin:0;padding:0}
.kr-tile li{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:6px;font-size:16px;line-height:1.35;padding:2px 0}
.kr-tile li .swatch{align-self:center}
.kr-tile .swatch{margin:0;flex:none}
.kr-tile .nm{flex:1 1 auto}
.kr-tile .sh{flex:none;margin-left:auto;font-variant-numeric:tabular-nums}
/* A tile is narrow (three in half the page): a long name with its marks keeps its line, and the share drops under it,
   right-aligned, rather than run into it. */
.kr-tile .reporting{margin:6px 0 0}
/* The chamber pages' filters (Kyle, 2026-11-03): a quiet "Filters" button that opens them; each group a label
   and two options in the map switch's style; what's showing under the button while any is on. */
.row-filters{margin:0 0 var(--nyf-space-2)}
.filter-box summary{display:inline-flex;align-items:center;gap:6px;cursor:pointer;list-style:none;font-size:14px;color:var(--nyf-grey-dark);border:1px solid var(--rule);padding:2px var(--nyf-space-1)}
.filter-box summary::-webkit-details-marker{display:none}
.filter-box summary::after{content:"";width:6px;height:6px;border:solid currentColor;border-width:0 1.5px 1.5px 0;transform:translateY(-2px) rotate(45deg)}
.filter-box[open] summary::after{transform:translateY(1px) rotate(-135deg)}
.filter-box summary:hover{color:var(--nyf-ink)}
.filter-body{display:flex;flex-wrap:wrap;gap:var(--nyf-space-1) var(--nyf-space-3);margin-top:var(--nyf-space-1)}
/* Over the table and the map, the page's full width, so the three groups fit on one line on a wide screen (Kyle,
   2026-11-04); the table and map start a step below. */
.row-filters{margin-bottom:var(--nyf-space-3)}
.filter-group{display:flex;align-items:center;gap:var(--nyf-space-1)}
.filter-label{font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:var(--nyf-grey)}
.row-filters .view-toggle{margin:0}
.row-filters .n{color:var(--nyf-grey);font-variant-numeric:tabular-nums}
.row-filters [aria-pressed="true"] .n{color:inherit}
.row-filters [data-filter="flips"] .n{color:inherit}   /* "Dem +2": one label, not a label and a count */
/* On a phone, each group on a line of its own, its buttons starting on one vertical line (Kyle, 2026-11-05). */
@media (max-width:599px){.filter-body{display:grid;grid-template-columns:max-content minmax(0,1fr);align-items:center;gap:var(--nyf-space-1)}
  .filter-group{display:contents}.row-filters .view-toggle{justify-self:start}}
.row-filters button:disabled{color:#aaa;cursor:default}.row-filters button:disabled .n{color:inherit}
.filter-count{margin:var(--nyf-space-1) 0 0;font-size:14px;color:var(--nyf-grey)}
.filter-clear{font:inherit;color:var(--nyf-blue);background:none;border:0;padding:0;text-decoration:underline;cursor:pointer}
tr[data-row][hidden]{display:none}
/* The chamber filters on the map (Kyle, 2026-11-03): a district left out is a flat light gray, so the state keeps its
   shape (faded, it all but vanished); a district shown keeps its color and gets an ink outline. */
.results-map .areas path[data-dim]{fill:#f6f4f0}
.results-map .edges path.pick{stroke:var(--nyf-ink);stroke-width:1.25}
.results-map .edges path.hot{stroke-width:2}
/* The section shelf (Kyle, 2026-11-03; menus 2026-11-05) is drawn by the shared .nyf-shelf in brand.css, its menus run by
   brand.js (2026-11-09, replacing this project's own .shelf rules, the same rules shared from here). */

/* The newsletter pop-up (site/signup.js; Kyle, 2026-11-04: as the Wisepops one, whose pageviews ran out): the photo,
   then the brand's yellow with the headline in the pop-up's blue, the line, the email field and the button. Over the
   page with a dim backdrop, centered; on a phone the width of the screen less 16px each side, scrolling if it's taller. */
.signup-wrap{position:fixed;inset:0;z-index:3000;display:flex;align-items:center;justify-content:center;padding:16px;box-sizing:border-box}
.signup-backdrop{position:absolute;inset:0;background:rgb(12 35 41 / 55%)}
/* A quick fade, the card rising 12px as it comes in (Kyle, 2026-11-04: as Wisepops's); out a little faster. The page
   isn't locked: it scrolls under the pop-up, as with Wisepops. Less motion asked for: a fade only. */
.signup-wrap{pointer-events:none}
.signup-wrap.in{pointer-events:auto}
.signup-backdrop,.signup-card{opacity:0;transition:opacity .15s ease-in,transform .15s ease-in}
.signup-card{transform:translateY(12px)}
.signup-wrap.in .signup-backdrop,.signup-wrap.in .signup-card{opacity:1;transform:none;transition-duration:.25s;transition-timing-function:ease-out}
@media (prefers-reduced-motion:reduce){.signup-card{transform:none}}
.signup-card{position:relative;width:min(420px,100%);max-height:100%;overflow-y:auto;overscroll-behavior:contain;background:var(--nyf-yellow);box-shadow:0 12px 40px rgb(0 0 0 / 35%);outline:none;-webkit-overflow-scrolling:touch}
.signup-img{display:block;width:100%;height:auto;aspect-ratio:3/2;object-fit:cover}
.signup-close{position:absolute;top:8px;right:8px;width:40px;height:40px;display:flex;align-items:center;justify-content:center;background:none;border:0;color:#fff;cursor:pointer;filter:drop-shadow(0 1px 2px rgb(0 0 0 / 50%))}
.signup-close:focus-visible{outline:2px solid #fff;outline-offset:2px}
.signup-body{padding:var(--nyf-space-3) var(--nyf-space-3) var(--nyf-space-4);text-align:center}
.signup-card h2{margin:0 0 var(--nyf-space-1);font-family:var(--nyf-font-headline);font-weight:400;text-transform:uppercase;color:var(--nyf-blue-mid);font-size:34px;line-height:1.05;letter-spacing:.01em}
.signup-dek{margin:0 0 var(--nyf-space-3);font-family:var(--nyf-font-sans);font-size:17px;line-height:1.35;color:var(--nyf-ink)}
.signup-form{display:flex;flex-direction:column;gap:var(--nyf-space-1);max-width:340px;margin:0 auto}
.signup-form input{box-sizing:border-box;width:100%;font:inherit;font-family:var(--nyf-font-sans);font-size:16px;padding:12px 14px;border:1px solid rgb(0 0 0 / 15%);border-radius:10px;background:#fff;color:var(--nyf-ink)}
.signup-form input:focus{outline:2px solid var(--nyf-blue-mid);outline-offset:1px}
.signup-form button{font:inherit;font-family:var(--nyf-font-sans);font-size:18px;padding:12px;border:0;border-radius:10px;background:var(--nyf-blue-mid);color:#fff;cursor:pointer}
.signup-form button:hover{background:#28508c}   /* a darker shade of --nyf-blue-mid */
.signup-form button:disabled{opacity:.7;cursor:wait}
.signup-msg{margin:0;font-family:var(--nyf-font-sans);font-size:14px;color:var(--nyf-ink)}
.signup-msg.err{color:#a30000}
.signup-thanks{margin:var(--nyf-space-1) 0;font-family:var(--nyf-font-sans);font-size:18px;line-height:1.35;color:var(--nyf-ink)}
.signup-sr,.signup-hp{position:absolute!important;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
@media (max-width:599px){.signup-card h2{font-size:30px}.signup-dek{font-size:16px}.signup-body{padding:var(--nyf-space-2) var(--nyf-space-2) var(--nyf-space-3)}}
.signup-msg:empty{display:none}
html.signup-open .feed-fab{visibility:hidden}

/* The turnout and early voting tables on a phone (Kyle, 2026-11-05): one line a county, the share the thing to read. */
.turnout-table .tv-of{display:none}
