/**
 * Early Vote Tracker — /early-vote
 *
 * Namespace .ei-ev-*. Every colour, radius and shadow is an ElectIndex token,
 * so the page follows the site into dark mode with everything else and a change
 * to the design system reaches it for free. Page chrome reuses the forecast
 * viewer's hero + deck (.ei-fc__hero / .ei-fc__deck) and its card and table
 * primitives (.ei-fc-card, .ei-fc-table, .ei-fc-th, .ei-fc-voteshare), so the
 * tracker reads as another room in the same building.
 *
 * ------------------------------------------------------------------------
 * FIVE SHAPES, AND EACH ONE MEANS EXACTLY ONE THING
 *
 * This page publishes five different kinds of number about the same ballots,
 * and a reader who confuses two of them is worse informed than one who read
 * nothing. Colour alone cannot carry that, so each kind gets its own GEOMETRY
 * and a reader can tell them apart from across the room:
 *
 *   a REPORTED party split   .ei-fc-voteshare — a solid stacked bar. Every
 *                            pixel filled; the boundary between navy and red
 *                            IS the number.
 *   a MODELLED split         .ei-ev-est — a hatched interval on an axis, in
 *                            graphite. Most of the track empty, and the empty
 *                            part is the point.
 *   a PAST RESULT            .ei-ev-mbar — a bar out from the centre of an
 *                            empty track, one colour. A margin, not a
 *                            partition.
 *   a MEASURED CHANGE        .ei-ev-shift — a signed number and no bar at all,
 *                            because a fourth bar would start eroding the
 *                            first three.
 *   a THOUGHT EXPERIMENT     .ei-ev-what — outline only, no fill, NO COLOUR.
 *                            The one achromatic object here, because it is the
 *                            least load-bearing thing on the page and should
 *                            look like it.
 *
 * ⚠️ Do not give any of these the treatment of another to "match the page".
 * The moment the model looks like the count, it starts being quoted as one.
 *
 * ⚠️ THE THOUGHT EXPERIMENT WAS PROMOTED and is now the FIRST block and the
 * LARGEST figure in an opened state panel — above the 2024 benchmark, which
 * became its supporting anchor. Size and position only. It is still outline,
 * still dotted, still achromatic, and the shape rule above is unchanged: the
 * biggest number on that panel must still be the one a reader can see at a
 * glance is not a measurement.
 *
 * TWO PALETTE DECISIONS THAT ARE LOAD-BEARING, NOT DECORATION
 *
 * 1. METHOD IS NEVER NAVY OR RED. Mail vs in-person is a teal/ochre pair, so it
 *    cannot be mistaken at a glance for a party bar.
 *
 * 2. PRIOR CYCLES ARE GREY, AND DIFFER BY DASH PATTERN. 2026 is the only
 *    coloured line on the cumulative chart; 2022 is dashed slate and 2024 is
 *    dotted lighter slate. Cycle is not a party, so it does not get a party
 *    colour, and the pattern carries the distinction for anyone who cannot
 *    separate the two greys.
 * ------------------------------------------------------------------------
 */

/* ==================================================================== */
/* TOKENS — one :root and one dark block. There used to be two of each,  */
/* because the estimate palette was appended in its own session; a       */
/* second :root three hundred lines down is how a token gets defined     */
/* twice with different values and nobody notices which one wins.        */
/* ==================================================================== */

:root {
	/* Voting method — see note 1 above. */
	--ei-ev-mail: #3f8f8a;
	--ei-ev-inperson: #c8862b;
	/* Prior cycles on the cumulative chart. */
	--ei-ev-2022: #6b7a91;
	--ei-ev-2024: #a3aec0;
	/* "Other party" / "no party" everywhere: the party bars, the legends, the
	   chart areas, the demographic strip. Was the literal #8a94a6 in five
	   places, one of which had drifted to #9aa7b8. */
	--ei-ev-oth: #8a94a6;

	/* Freshness / provenance badges. */
	--ei-ev-stale-ink: #8a5a00;
	--ei-ev-stale-bg: #fbf2d6;
	--ei-ev-stale-border: #e7cd85;
	--ei-ev-fresh-ink: #12694a;
	--ei-ev-fresh-bg: #e6f5ee;
	--ei-ev-fresh-border: #b6e0cd;

	/* Map palette — its OWN tokens, not the page's surfaces.
	   The generic surfaces are three near-identical near-whites in light mode
	   (#f5f7fa / #eef2f7 / #e2e8f0). Fine for a card edge; on a choropleth they
	   make land, borders and background indistinguishable and the map
	   effectively disappears. These are pulled apart deliberately. */
	--ei-ev-land: #dde5ef;      /* tracked, not yet open */
	--ei-ev-land-edge: #9fb0c6; /* outer edge, so the country reads as a shape */
	--ei-ev-hatch: #c2cfdf;     /* not tracked / no party registration */

	/* Tooltips sit on a dark ground in BOTH themes, so their party keys need
	   lifted values rather than the page's own navy and red. One set, used by
	   the map tip and the chart tip alike — they were two copies. */
	--ei-ev-tip-dem: #6ea8f0;
	--ei-ev-tip-rep: #f0736e;
	--ei-ev-tip-ind: #b088ec;
	--ei-ev-tip-oth: #9aa7b8;

	/* THE MODEL. Graphite, deliberately: not navy, not red, not the teal/ochre
	   the method bar owns, not the amber the stale badge owns. A model output
	   is not a party, not a source and not a freshness state. */
	--ei-ev-est-ink: #4f5a6d;
	--ei-ev-est-line: #8d99ad;
	--ei-ev-est-bg: #f4f6f9;
	--ei-ev-est-border: #b9c3d1;
	--ei-ev-est-track: #e6ebf2;

	/* The thought experiment's dotted edge. Its OWN token, not --ei-border:
	   the block was promoted to the top of the state panel and needed a
	   slightly more present outline to hold that position — which is the ONLY
	   thing it was allowed to gain. Still achromatic, still dotted, still no
	   fill. Bigger, never more solid. */
	--ei-ev-what-edge: #aeb8c6;

	/* ONE SPACING SCALE FOR THE STATE PANEL.
	   These were five different numbers doing one job: cards padded .8, .95,
	   1.05, 1.35 and 1.45rem, separated by 0, .7, .9 and 1.1rem. Nothing chose
	   those values; each was set when its card was written. */
	--ei-ev-card-gap: 1rem;      /* between one card and the next */
	--ei-ev-card-pad-y: 1rem;    /* inside a card, top and bottom */
	--ei-ev-card-pad-x: 1.1rem;  /* inside a card, left and right */
	--ei-ev-block-gap: .8rem;    /* between blocks within one card */
}

[data-theme="dark"] {
	--ei-ev-mail: #5cc3bb;
	--ei-ev-inperson: #e0a544;
	--ei-ev-2022: #8b99ae;
	--ei-ev-2024: #5f6c80;
	--ei-ev-oth: #7d8798;

	--ei-ev-stale-ink: #f0c64e;
	--ei-ev-stale-bg: rgba(212, 160, 40, .16);
	--ei-ev-stale-border: rgba(212, 160, 40, .42);
	--ei-ev-fresh-ink: #5fce90;
	--ei-ev-fresh-bg: rgba(34, 160, 105, .14);
	--ei-ev-fresh-border: rgba(34, 160, 105, .36);

	--ei-ev-land: #273244;
	--ei-ev-land-edge: #4a5b73;
	--ei-ev-hatch: #3c4a5e;

	--ei-ev-est-ink: #aab6c8;
	--ei-ev-est-line: #7c8a9f;
	--ei-ev-est-bg: rgba(140, 156, 180, .10);
	--ei-ev-est-border: rgba(140, 156, 180, .42);
	--ei-ev-est-track: rgba(140, 156, 180, .16);

	--ei-ev-what-edge: #58657c;
}

/* ==================================================================== */
/* Page chrome                                                          */
/* ==================================================================== */

/* NOTE: three rules scoped to `.ei-earlyvote-page` used to sit here and are
   gone as exact duplicates. That class is real — templates/page-early-vote.html
   puts it on the page's <main> — but it puts `ei-forecasts-page` on the SAME
   element, and style.css already gives that class the identical background and
   the identical `margin-top: 0; padding: 0`. The third rule cleared the post
   content's width constraint, which the full-width template already does:
   verified in the browser, `.entry-content` computes to `max-width: none;
   margin: 0; padding: 0` and a full 1440px without it, exactly as /forecasts
   does with no such rule of its own. Two spellings of one instruction on one
   element is how they drift. */
.ei-ev-root *, .ei-ev-root *::before, .ei-ev-root *::after { box-sizing: border-box; }

.ei-ev-shell { max-width: 1240px; margin: 0 auto; display: grid; gap: clamp(1rem, 2vw, 1.5rem); }

/* Tabs. The switcher itself is .ei-fc__switcher, borrowed wholesale from the
   forecast viewer so the two controls cannot drift apart; only the panel
   plumbing is local. Centred, matching the forecast viewer's own placement. */
.ei-ev-switcher { margin: 0 auto; justify-content: center; }
.ei-ev-panel { display: grid; gap: clamp(1rem, 2vw, 1.5rem); }

/* A slot can hold MORE than one card — the Overview stacks several. The panel's
   gap only separates its own direct children (the slots), so without this the
   cards inside a slot sit flush: they carry margin:0 by design, on the
   assumption that whatever contains them owns the rhythm. */
.ei-ev-slot { display: grid; gap: clamp(1rem, 2vw, 1.5rem); align-content: start; }
.ei-ev-slot:empty { display: none; }
.ei-ev-card { margin: 0; }

/* ==================================================================== */
/* SHARED CARD FURNITURE                                                */
/*                                                                      */
/* One header, one note, one caption, one blank, one figure. The tracker */
/* had grown three headers (.ei-ev-secth on the Overview,                */
/* .ei-ev-tablehead__title on the board, .ei-ev-maph on the maps) — the  */
/* same object at three sizes with three sets of margins, because each   */
/* was written in the session that needed it.                            */
/* ==================================================================== */

.ei-ev-cardhead { margin: 0 0 1rem; padding-bottom: .7rem; border-bottom: 1px solid var(--ei-border); }
.ei-ev-cardhead__h {
	margin: 0; font-size: 1.06rem; font-weight: 800; letter-spacing: -.012em;
	color: var(--ei-heading); display: flex; align-items: baseline; flex-wrap: wrap; gap: .5rem;
}
.ei-ev-cardhead__sub { margin: .3rem 0 0; font-size: .85rem; line-height: 1.55; color: var(--ei-muted); max-width: 80ch; }

.ei-ev-note { margin: .7rem 0 0; font-size: .79rem; line-height: 1.5; color: var(--ei-muted); max-width: 76ch; }

/* An unreported figure. Deliberately quiet AND deliberately present — the whole
   point is that a blank is visible as a blank, not filled in with a zero. */
.ei-ev-na { color: var(--ei-muted); font-size: .82rem; font-style: italic; }

/* The party-registration caption. Carried on every surface that shows a party
   split; styled as a standing note, not a warning banner, because it is always
   true rather than exceptional. */
.ei-ev-caution {
	margin: .6rem 0 0; padding-left: .8rem; border-left: 3px solid var(--ei-red);
	font-size: .84rem; line-height: 1.5; font-weight: 600; color: var(--ei-heading);
}

.ei-ev-figs { display: flex; flex-wrap: wrap; gap: .3rem 1.6rem; margin-top: .8rem; }
.ei-ev-fig { display: flex; flex-direction: column; gap: .1rem; }
.ei-ev-fig__v { font-size: 1.15rem; font-weight: 800; line-height: 1.1; color: var(--ei-heading); font-variant-numeric: tabular-nums; }
.ei-ev-fig__l { font-size: .74rem; color: var(--ei-muted); }

/* The Overview's one outbound link, where the state board used to be. */
.ei-ev-more__link {
	justify-self: center; font-size: .88rem; font-weight: 700; color: var(--ei-navy);
	text-decoration: none; padding: .35rem .2rem;
}
.ei-ev-more__link:hover { text-decoration: underline; }
[data-theme="dark"] .ei-ev-more__link { color: var(--ei-link); }

/* A disclosure holding the tail of a long list (the pre-season schedule). */
.ei-ev-more { margin-top: .6rem; }
.ei-ev-more__sum { cursor: pointer; font-size: .82rem; font-weight: 700; color: var(--ei-navy); }
.ei-ev-more__sum:focus-visible { outline: 2px solid var(--ei-navy); outline-offset: 3px; }

/* ------------------------------------------------------------------ */
/* Badges                                                              */
/* ------------------------------------------------------------------ */

.ei-ev-badges { display: flex; flex-wrap: wrap; gap: .3rem; }
.ei-ev-badge {
	display: inline-flex; align-items: center; font-size: .68rem; font-weight: 700;
	padding: .18rem .5rem; border-radius: 999px; white-space: nowrap;
	border: 1px solid var(--ei-border); background: var(--ei-surface); color: var(--ei-muted);
}
[data-theme="dark"] .ei-ev-badge { background: var(--ei-surface-2); }
/* Tier 1 = the state itself. The only badge that gets brand navy, because it is
   the only source we can call authoritative. */
.ei-ev-badge--tier.is-t1 { color: var(--ei-navy); border-color: color-mix(in srgb, var(--ei-navy) 32%, var(--ei-border)); }
/* The hand-entered tier, italicised so a compiled-by-hand row is never mistaken
   for a machine-read one. Tier 4 since civicAPI took 2 (2026-09-06). */
.ei-ev-badge--tier.is-t4 { font-style: italic; }
.ei-ev-badge--fresh { color: var(--ei-ev-fresh-ink); background: var(--ei-ev-fresh-bg); border-color: var(--ei-ev-fresh-border); }
.ei-ev-badge--stale { color: var(--ei-ev-stale-ink); background: var(--ei-ev-stale-bg); border-color: var(--ei-ev-stale-border); }
/* NOT YET OPEN is dashed, everywhere on this page. A dashed edge means
   "nothing here yet" and must never read the same as a solid card holding a
   zero. NOT TRACKED is solid and flat — nothing is coming, so nothing is
   pending. Those two badges are the whole visual distinction between the two
   states on the board, and they are three lines apart so they stay it. */
.ei-ev-badge--pending { color: var(--ei-muted); border-style: dashed; }
.ei-ev-badge--never { color: var(--ei-muted); background: var(--ei-surface-2); }
[data-theme="dark"] .ei-ev-badge--never { background: var(--ei-bg); }
.ei-ev-badge--error { color: var(--ei-red); border-color: color-mix(in srgb, var(--ei-red) 36%, var(--ei-border)); }
/* PARTIAL is the badge a reader must not skim, because a partial count is the
   one figure on this page that looks exactly like a complete one. It had no
   rule at all and rendered as the neutral default beside "State" and "1 day
   ago", which is where a caveat goes to be missed. */
.ei-ev-badge--partial {
	color: var(--ei-red); font-weight: 800;
	border-color: color-mix(in srgb, var(--ei-red) 40%, var(--ei-border));
	background: color-mix(in srgb, var(--ei-red) 7%, var(--ei-bg));
}
[data-theme="dark"] .ei-ev-badge--partial { background: color-mix(in srgb, var(--ei-red) 16%, transparent); }

/* ------------------------------------------------------------------ */
/* Bars and their keys                                                 */
/* ------------------------------------------------------------------ */

/* Party: reuses .ei-fc-voteshare wholesale (segments, colours, the dot key) and
   only trims the height for a table row. */
.ei-ev-bar.ei-fc-voteshare { height: 14px; border-radius: 999px; margin-top: 0; font-size: .6rem; }
.ei-ev-partybar { min-width: 0; }
.ei-ev-bar.ei-fc-voteshare .ei-fc-voteshare__seg { min-width: 0; overflow: hidden; }

.ei-ev-bar--method { display: flex; height: 14px; border-radius: 999px; overflow: hidden; background: var(--ei-surface-2); }
.ei-ev-bar__seg { display: block; height: 100%; }
.ei-ev-bar__seg.is-mail { background: var(--ei-ev-mail); }
.ei-ev-bar__seg.is-inperson { background: var(--ei-ev-inperson); }
.ei-ev-bar__legend { display: flex; flex-wrap: wrap; gap: .1rem .7rem; margin-top: .3rem; font-size: .72rem; color: var(--ei-muted); }
.ei-ev-bar__key { display: inline-flex; align-items: center; gap: .3rem; white-space: nowrap; }
.ei-ev-bar__dot, .ei-ev-demo__dot { width: .55rem; height: .55rem; border-radius: 2px; flex: 0 0 auto; }
.ei-ev-bar__dot.is-mail { background: var(--ei-ev-mail); }
.ei-ev-bar__dot.is-inperson { background: var(--ei-ev-inperson); }
/* UNSCOPED, all four of them. These keys appear in three different containers —
   the state charts, the state board and the Overview panels — and an
   ancestor-scoped rule silently misses whichever one it was not written for.
   .is-oth used to be scoped to .ei-ev-split alone for exactly no reason. */
.ei-ev-bar__key.is-dem { color: var(--ei-navy); }
.ei-ev-bar__key.is-rep { color: var(--ei-red); }
.ei-ev-bar__key.is-ind { color: var(--ei-ind); }
.ei-ev-bar__key.is-oth { color: var(--ei-muted); }

/* .ei-fc-voteshare__dot ships geometry only — its colour modifiers live in the
   forecast views and were never defined for these keys, so the party legend
   rendered as invisible squares.
   UNSCOPED on purpose, for the same reason as the keys above: the table's dots
   were invisible for weeks because the rule was written under one ancestor.
   ev.css loads only on /early-vote/, where the forecast viewer that owns this
   class is not present, so there is nothing to collide with. */
.ei-fc-voteshare__dot.is-dem { background: var(--ei-navy); }
.ei-fc-voteshare__dot.is-rep { background: var(--ei-red); }
.ei-fc-voteshare__dot.is-ind { background: var(--ei-ind); }
.ei-fc-voteshare__dot.is-oth { background: var(--ei-ev-oth); }

/* ==================================================================== */
/* THE PAST RESULT — .ei-ev-past / .ei-ev-mbar                          */
/*                                                                      */
/* How a state (or the board's whole set of them) actually voted in     */
/* 2024, and what share of that vote came in early. It is the context   */
/* that makes an early-vote count readable at all: the same number of   */
/* ballots is most of one state's electorate and a slow morning in      */
/* another.                                                             */
/*                                                                      */
/* THE BAR GROWS OUT FROM THE CENTRE. It encodes a margin, not a        */
/* partition, and it is the only diverging-from-centre mark here — so a */
/* result cannot be read as the stacked party bar above it.             */
/* ==================================================================== */

.ei-ev-past {
	margin: 0; padding: var(--ei-ev-card-pad-y) var(--ei-ev-card-pad-x);
	border: 1px solid var(--ei-border); border-radius: var(--ei-radius);
	background: var(--ei-surface);
}
[data-theme="dark"] .ei-ev-past { background: var(--ei-surface-2); }
.ei-ev-past__h { margin: 0 0 .7rem; font-size: .84rem; font-weight: 700; color: var(--ei-heading); }
/* Aligned by the TOP, so the three figures line up on the number a reader
   actually looks at. flex-end aligned them by their bottoms instead, and the
   margin column is taller than the others (it carries the bar underneath), so
   the two plain figures were pushed down out of line with it. */
.ei-ev-past__figs { display: flex; flex-wrap: wrap; gap: .9rem 2.2rem; align-items: flex-start; }
.ei-ev-past__fig { display: flex; flex-direction: column; gap: .15rem; min-width: 7rem; }
.ei-ev-past__v {
	font-size: 1.5rem; font-weight: 800; line-height: 1.05; letter-spacing: -.02em;
	color: var(--ei-heading); font-variant-numeric: tabular-nums;
}
/* The one place on this page a party colour may carry a NUMBER rather than a
   bar, because the number is a party's own margin in a counted election. */
.ei-ev-past__v.is-dem { color: var(--ei-navy); }
.ei-ev-past__v.is-rep { color: var(--ei-red); }
.ei-ev-past__l { font-size: .74rem; line-height: 1.35; color: var(--ei-muted); max-width: 18ch; }
.ei-ev-past__p { margin: .8rem 0 0; font-size: .8rem; line-height: 1.55; color: var(--ei-muted); max-width: 82ch; }

.ei-ev-mbar { margin-top: .4rem; }
.ei-ev-mbar__track {
	position: relative; height: 8px; border-radius: 999px;
	background: var(--ei-surface-2); overflow: hidden;
}
[data-theme="dark"] .ei-ev-mbar__track { background: var(--ei-bg); }
.ei-ev-mbar__mid {
	position: absolute; left: 50%; top: 0; bottom: 0; width: 1px;
	background: var(--ei-ev-land-edge);
}
.ei-ev-mbar__fill { position: absolute; top: 0; bottom: 0; }
.ei-ev-mbar__fill.is-dem { left: 50%; background: var(--ei-navy); border-radius: 0 999px 999px 0; }
.ei-ev-mbar__fill.is-rep { right: 50%; background: var(--ei-red); border-radius: 999px 0 0 999px; }

/* The same component, compressed into a table cell. */
.ei-ev-td.is-past { min-width: 150px; }
.ei-ev-pastcell { display: grid; gap: .12rem; }
.ei-ev-pastcell__m { font-weight: 700; font-size: .92rem; font-variant-numeric: tabular-nums; }
.ei-ev-pastcell__m.is-dem { color: var(--ei-navy); }
.ei-ev-pastcell__m.is-rep { color: var(--ei-red); }
.ei-ev-pastcell__m.is-even { color: var(--ei-muted); }
.ei-ev-pastcell__e { font-size: .71rem; color: var(--ei-muted); font-variant-numeric: tabular-nums; }
.ei-ev-pastcell__e.is-na { font-style: italic; }
.ei-ev-pastcell .ei-ev-mbar { margin-top: .18rem; }

/* ==================================================================== */
/* OVERVIEW — the hero                                                  */
/* ==================================================================== */

.ei-ev-hero { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.5rem; }
@media (min-width: 900px) {
	.ei-ev-hero {
		grid-template-columns: minmax(230px, 300px) minmax(0, 1fr);
		gap: clamp(1.5rem, 3vw, 2.75rem);
		align-items: start;
	}
	/* A hairline between the count and the pace it is being judged against.
	   They are two halves of one sentence, so they share a card and a rule
	   rather than two cards and a gap. */
	.ei-ev-hero > .ei-ev-hero__body {
		border-left: 1px solid var(--ei-border);
		padding-left: clamp(1.5rem, 3vw, 2.75rem);
	}
	/* The 2024 benchmark spans both columns: it is context for the count AND
	   for the pace, so it belongs to neither. */
	.ei-ev-hero > .ei-ev-past { grid-column: 1 / -1; }
}

/* THE PAGE'S ONE BOLD MOVE. Tabular figures at a tight track so a change of
   digit does not shift the layout. */
.ei-ev-hero__figure { min-width: 0; }
.ei-ev-big {
	font-size: clamp(2.8rem, 7vw, 4.4rem); font-weight: 800; line-height: .92;
	letter-spacing: -.05em; color: var(--ei-heading); font-variant-numeric: tabular-nums;
}
.ei-ev-big__cap { margin: .5rem 0 0; font-size: .95rem; color: var(--ei-muted); max-width: 24ch; }
.ei-ev-big__move {
	margin: .55rem 0 0; font-size: .84rem; font-weight: 700; line-height: 1.4;
	color: var(--ei-ev-fresh-ink); font-variant-numeric: tabular-nums; max-width: 34ch;
}
/* A reported zero keeps its line and loses its colour: nothing arrived, which
   is a fact about the day and not a failure to read one. */
.ei-ev-big__move.is-quiet { color: var(--ei-muted); font-weight: 600; }
.ei-ev-big__meta { margin-top: 1rem; padding-top: .8rem; border-top: 1px solid var(--ei-border); display: grid; gap: .4rem; }
.ei-ev-big__dte { margin: 0; font-size: .82rem; font-weight: 700; color: var(--ei-navy); }
.ei-ev-big__cov { margin: 0; font-size: .78rem; line-height: 1.45; color: var(--ei-muted); max-width: 30ch; }
/* Rule 5, said out loud next to the number it changed. */
.ei-ev-big__excl { margin: 0; font-size: .78rem; line-height: 1.45; color: var(--ei-muted); max-width: 32ch; }

/* --------------------------------------------------------- the pace rail */
/* Was two objects: a boxed "verdict band" holding the ratio and a sentence,
   and directly beneath it a second block with its own heading and its own
   footnote holding the three bars that ratio is computed FROM. Two boxes, two
   headings, two notes, one fact. The verdict is the rail's headline now and
   the bars are its evidence. */

.ei-ev-pace { min-width: 0; }
.ei-ev-pace__head {
	--ei-ev-pace-ink: var(--ei-heading);
	--ei-ev-pace-bg: var(--ei-surface);
	--ei-ev-pace-border: var(--ei-border);
	display: grid; grid-template-columns: auto minmax(0, 1fr);
	gap: .3rem clamp(1rem, 2.4vw, 1.6rem); align-items: center;
	margin: 0 0 1.15rem; padding: .95rem clamp(1rem, 2.2vw, 1.2rem);
	border: 1px solid var(--ei-ev-pace-border); border-radius: var(--ei-radius-lg);
	background: var(--ei-ev-pace-bg);
}
[data-theme="dark"] .ei-ev-pace__head { --ei-ev-pace-bg: var(--ei-surface-2); }
/* AHEAD IS GREEN, BEHIND IS AMBER, NEVER RED. Every other bar on this page uses
   navy for Democrats and red for Republicans, so a red band reading "well
   behind 2022" would be read as a party statement rather than a turnout one.
   Both tones are the freshness badges' own, which already carry light AND dark
   values, so no new colour enters the system. */
.ei-ev-pace__head.is-ahead,
.ei-ev-pace__head.is-well-ahead {
	--ei-ev-pace-ink: var(--ei-ev-fresh-ink);
	--ei-ev-pace-bg: var(--ei-ev-fresh-bg);
	--ei-ev-pace-border: var(--ei-ev-fresh-border);
}
.ei-ev-pace__head.is-behind,
.ei-ev-pace__head.is-well-behind {
	--ei-ev-pace-ink: var(--ei-ev-stale-ink);
	--ei-ev-pace-bg: var(--ei-ev-stale-bg);
	--ei-ev-pace-border: var(--ei-ev-stale-border);
}
/* No ratio to print: the figure column disappears rather than standing empty. */
.ei-ev-pace__head:not(:has(.ei-ev-pace__fig)) { grid-template-columns: minmax(0, 1fr); }
.ei-ev-pace__fig { display: flex; flex-direction: column; align-items: flex-start; }
/* Deliberately the same setting as .ei-ev-count__num, one size down: before the
   season the countdown fills this slot and after it opens the pace read does,
   so the two must read as the same object changing state. */
.ei-ev-pace__num {
	font-size: clamp(2rem, 4.6vw, 2.75rem); font-weight: 800; line-height: .9;
	letter-spacing: -.05em; color: var(--ei-ev-pace-ink); font-variant-numeric: tabular-nums;
}
.ei-ev-pace__of { margin-top: .3rem; font-size: .72rem; line-height: 1.3; color: var(--ei-muted); max-width: 9ch; }
.ei-ev-pace__say { min-width: 0; }
.ei-ev-pace__label { margin: 0; font-size: 1.02rem; font-weight: 800; letter-spacing: -.015em; color: var(--ei-heading); }
.ei-ev-pace__p { margin: .28rem 0 0; font-size: .88rem; line-height: 1.55; color: var(--ei-text); max-width: 58ch; }

@media (max-width: 560px) {
	.ei-ev-pace__head { grid-template-columns: minmax(0, 1fr); }
	.ei-ev-pace__of { max-width: none; }
}

/* The evidence rows. */
.ei-ev-cmp { min-width: 0; }
.ei-ev-cmp__row { display: grid; grid-template-columns: 3.2rem minmax(0, 1fr) 4.4rem; gap: .7rem; align-items: center; margin-bottom: .55rem; }
.ei-ev-cmp__label { font-size: .85rem; font-weight: 700; color: var(--ei-muted); font-variant-numeric: tabular-nums; }
.ei-ev-cmp__track { height: 12px; border-radius: 999px; background: var(--ei-surface-2); overflow: hidden; }
[data-theme="dark"] .ei-ev-cmp__track { background: var(--ei-bg); }
.ei-ev-cmp__fill { display: block; height: 100%; border-radius: 999px; background: var(--ei-ev-2024); }
.ei-ev-cmp__row.is-now .ei-ev-cmp__fill { background: var(--ei-navy); }
.ei-ev-cmp__row.is-2022 .ei-ev-cmp__fill { background: var(--ei-ev-2022); }
.ei-ev-cmp__val { text-align: right; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ei-heading); font-size: .92rem; }
.ei-ev-cmp__note { margin: .9rem 0 0; font-size: .8rem; line-height: 1.5; color: var(--ei-muted); max-width: 72ch; }
/* An unreported comparison row keeps its label and loses its bar. A zero-width
   track under "2024" reads as "2024 had none", which is the blank rule failing
   in the first place a reader looks. */
.ei-ev-cmp__na { grid-column: 2 / -1; font-size: .8rem; font-style: italic; color: var(--ei-muted); }
/* The delta chip takes a grid row of its own under the bar it annotates. */
.ei-ev-delta { grid-column: 2 / -1; margin-top: -.2rem; font-size: .78rem; font-weight: 700; line-height: 1.25; }
.ei-ev-delta.is-up { color: var(--ei-green); }
.ei-ev-delta.is-down { color: var(--ei-red); }
.ei-ev-delta.is-level { color: var(--ei-muted); }

/* ---------------------------------------------------- the empty states */

/* The countdown. Days-to-election is the axis every chart below is drawn on,
   so before the season starts the same number is the headline. */
.ei-ev-count {
	padding: 1.35rem 1.5rem 1.15rem;
	border-radius: var(--ei-radius-lg);
	background: linear-gradient(150deg, var(--ei-surface) 0%, var(--ei-surface-2) 100%);
	border: 1px solid var(--ei-border);
}
[data-theme="dark"] .ei-ev-count { background: linear-gradient(150deg, var(--ei-surface-2) 0%, var(--ei-bg) 100%); }
.ei-ev-count__fig { display: flex; align-items: baseline; gap: .5rem; }
.ei-ev-count__num {
	font-size: clamp(3.4rem, 8vw, 5rem); font-weight: 800; line-height: .9;
	letter-spacing: -.05em; color: var(--ei-navy); font-variant-numeric: tabular-nums;
}
.ei-ev-count__unit { font-size: 1.15rem; font-weight: 700; color: var(--ei-muted); }
.ei-ev-count__cap { margin: .7rem 0 0; font-size: .88rem; line-height: 1.45; color: var(--ei-muted); max-width: 22ch; }

.ei-ev-hero__body { min-width: 0; }
.ei-ev-hero__title { margin: 0; font-size: clamp(1.3rem, 2.2vw, 1.65rem); font-weight: 800; letter-spacing: -.02em; color: var(--ei-heading); }
.ei-ev-hero__lede { margin: .6rem 0 0; font-size: 1rem; line-height: 1.6; color: var(--ei-text); max-width: 62ch; }
.ei-ev-hero__note { margin: .8rem 0 0; font-size: .8rem; color: var(--ei-muted); }

/* What will appear here — the empty state's real content. Hairline-ruled rather
   than boxed into three more cards: these are notes about the page, not
   objects on it. */
.ei-ev-promise { list-style: none; margin: 1.4rem 0 0; padding: 0; display: grid; gap: 0; }
.ei-ev-promise__item { padding: .95rem 0; border-top: 1px solid var(--ei-border); }
.ei-ev-promise__item:last-child { padding-bottom: 0; }
.ei-ev-promise__h { margin: 0 0 .2rem; font-size: .95rem; font-weight: 700; color: var(--ei-heading); }
.ei-ev-promise__p { margin: 0; font-size: .89rem; line-height: 1.55; color: var(--ei-muted); max-width: 66ch; }

/* Opening schedule (pre-season, when the meta file is live but nothing is). */
.ei-ev-sched { list-style: none; margin: 1.2rem 0 0; padding: 0; display: grid; gap: 0; }
.ei-ev-sched__item {
	display: grid; grid-template-columns: 2.6rem minmax(0, 1fr) auto auto; gap: .5rem .9rem;
	align-items: baseline; padding: .55rem 0; border-top: 1px solid var(--ei-border); font-size: .9rem;
}
.ei-ev-sched__st { font-weight: 800; color: var(--ei-navy); letter-spacing: .02em; }
.ei-ev-sched__name { color: var(--ei-heading); min-width: 0; }
.ei-ev-sched__date { color: var(--ei-text); font-variant-numeric: tabular-nums; }
/* A date the state has not published. Italic, so it reads as an absence rather
   than as a value we are quoting. */
.ei-ev-sched__date.is-unknown { color: var(--ei-muted); font-style: italic; }
.ei-ev-sched__dte { color: var(--ei-muted); font-size: .8rem; font-variant-numeric: tabular-nums; }
@media (max-width: 560px) {
	.ei-ev-sched__item { grid-template-columns: 2.4rem minmax(0, 1fr) auto; }
	.ei-ev-sched__dte { display: none; }
}

/* ---------------------------------------------------- the curve + splits */

.ei-ev-curvecard .ei-ev-chart { margin-top: .2rem; }
/* The right edge of this chart is today, not Election Day — the prior cycles
   are clipped to where 2026 has reached. */
.ei-ev-axislab.is-today { fill: var(--ei-navy); font-style: normal; font-weight: 700; font-size: 10px; }
.ei-ev-dot.is-2022 { fill: var(--ei-ev-2022); stroke: var(--ei-bg); stroke-width: 2; }
.ei-ev-dot.is-2024 { fill: var(--ei-ev-2024); stroke: var(--ei-bg); stroke-width: 2; }

/* THE TWO SPLIT PANELS ARE ONE CARD, DIVIDED BY A HAIRLINE, not two cards side
   by side. They answer one question — how the ballots are arriving — and boxing
   each separately would imply they are independent readings. */
.ei-ev-splits { display: grid; gap: 1.3rem; }
@media (min-width: 800px) {
	.ei-ev-splits { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(1.5rem, 3vw, 2.4rem); }
	.ei-ev-splits > .ei-ev-split + .ei-ev-split {
		border-left: 1px solid var(--ei-border);
		padding-left: clamp(1.5rem, 3vw, 2.4rem);
	}
}
@media (max-width: 799px) {
	.ei-ev-splits > .ei-ev-split + .ei-ev-split { border-top: 1px solid var(--ei-border); padding-top: 1.2rem; }
}
.ei-ev-split { min-width: 0; }
.ei-ev-split__h { margin: 0 0 .6rem; font-size: .88rem; font-weight: 700; line-height: 1.4; color: var(--ei-heading); }
/* Card-sized, not table-row-sized: .ei-ev-bar is trimmed to 14px for a table
   cell, and these two bars are the panel's subject. */
.ei-ev-split .ei-ev-bar.ei-fc-voteshare,
.ei-ev-split .ei-ev-bar--method { height: 20px; border-radius: 999px; font-size: .68rem; }
.ei-ev-split .ei-ev-bar__legend { margin-top: .45rem; font-size: .78rem; }

/* ==================================================================== */
/* THE STATE BOARD                                                      */
/* ==================================================================== */

.ei-ev-tablecard { padding: 0; overflow: hidden; }
.ei-ev-tablehead { padding: 1.15rem 1.35rem .9rem; border-bottom: 1px solid var(--ei-border); }
/* Inside the board's own head the shared header loses its rule — the head
   already has one, and two hairlines 40px apart is a mistake, not a rhythm. */
.ei-ev-tablehead .ei-ev-cardhead { margin: 0; padding-bottom: 0; border-bottom: 0; }
.ei-ev-tablehead__count { margin: .8rem 0 0; font-size: .8rem; color: var(--ei-muted); }

/* ------------------------------------------------------- the scan strip */
/* Deliberately the SAME control as .ei-ev-mode — rounded, hairline-bordered,
   filled navy with white text when pressed — so the page has two button styles
   (the tab switcher and this pill) and not a third invented for one row.
   The count is a pill INSIDE the pill rather than a number glued to the label,
   because "All15" reads as a word and the number is the half a reader scans
   for. */
.ei-ev-filters { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .85rem; }
.ei-ev-filter {
	display: inline-flex; align-items: center; gap: .45rem;
	font: inherit; font-size: .8rem; font-weight: 700; cursor: pointer;
	padding: .3rem .38rem .3rem .78rem; border-radius: 999px;
	border: 1px solid var(--ei-border); background: var(--ei-surface);
	color: var(--ei-muted);
	transition: background .12s ease, color .12s ease, border-color .12s ease;
}
[data-theme="dark"] .ei-ev-filter { background: var(--ei-surface-2); }
.ei-ev-filter:hover {
	color: var(--ei-heading);
	border-color: color-mix(in srgb, var(--ei-navy) 32%, var(--ei-border));
}
.ei-ev-filter:focus-visible { outline: 2px solid var(--ei-navy); outline-offset: 2px; }
.ei-ev-filter__lab { white-space: nowrap; }
/* Tinted from the chip's OWN ink rather than the page background: --ei-bg is
   nearly black in dark mode, so the pill read as a second button sitting inside
   the first instead of as a count belonging to the label. */
.ei-ev-filter__n {
	display: inline-flex; align-items: center; justify-content: center;
	min-width: 1.5rem; padding: .08rem .38rem; border-radius: 999px;
	font-size: .72rem; font-weight: 800; font-variant-numeric: tabular-nums;
	line-height: 1.25;
	background: color-mix(in srgb, currentColor 12%, transparent);
	color: inherit;
}
[data-theme="dark"] .ei-ev-filter__n { background: color-mix(in srgb, currentColor 16%, transparent); }
/* The active chip, matching .ei-ev-mode[aria-pressed="true"] exactly. */
.ei-ev-filter[aria-pressed="true"] { background: var(--ei-navy); border-color: var(--ei-navy); color: #fff; }
.ei-ev-filter[aria-pressed="true"] .ei-ev-filter__n { background: rgba(255, 255, 255, .24); color: #fff; }

/* ----------------------------------------------------------- the table */

.ei-ev-tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.ei-ev-table { min-width: 940px; }
.ei-ev-th { white-space: nowrap; }
.ei-ev-th.is-num { text-align: right; }
.ei-ev-th__caret { margin-left: .3rem; font-size: .6rem; color: var(--ei-navy); }
.ei-ev-tr { border-bottom: 1px solid var(--ei-border); cursor: pointer; transition: background .12s ease; }
.ei-ev-tr:hover, .ei-ev-tr:focus-visible { background: var(--ei-surface); outline: none; }
[data-theme="dark"] .ei-ev-tr:hover, [data-theme="dark"] .ei-ev-tr:focus-visible { background: var(--ei-bg); }
.ei-ev-tr:focus-visible { box-shadow: inset 3px 0 0 var(--ei-navy); }
/* A row with nothing to report recedes. It is quieted, never hidden. */
.ei-ev-tr.is-quiet { opacity: .72; }
/* Rows here are reference, not navigation — no pointer, no hover lift. */
.ei-ev-tr.is-static { cursor: default; }
.ei-ev-tr.is-static:hover { background: transparent; }

/* A validation row that is SHOWN but not averaged in. Set back rather than
   struck through: it is a real measurement and the most informative row in the
   table, it simply is not one twelfth of a mean it would misprice. */
.ei-ev-tr.is-outofrange { opacity: .72; }
.ei-ev-tr.is-outofrange .ei-ev-td.is-series { font-style: italic; }
.ei-ev-td { padding: .7rem 1rem; vertical-align: middle; }
.ei-ev-td.is-num { text-align: right; font-variant-numeric: tabular-nums; }
.ei-ev-td.is-wide { min-width: 190px; }
.ei-ev-tr__name { display: block; font-weight: 700; color: var(--ei-heading); }
.ei-ev-tr__code { display: block; font-size: .73rem; color: var(--ei-muted); font-variant-numeric: tabular-nums; }
/* The short coverage signal (Maine's "Reported by municipality", South Dakota's
   "No county breakdown"). Italic and quiet: it qualifies the row, it is not a
   second name for the state. The full note is on its title. */
.ei-ev-tr__flag {
	display: block; margin-top: .12rem; max-width: 22ch;
	font-size: .71rem; font-style: italic; line-height: 1.35; color: var(--ei-muted);
}
.ei-ev-tr__ballots { display: block; font-weight: 700; color: var(--ei-heading); }
.ei-ev-tr__new { display: block; font-size: .73rem; color: var(--ei-muted); }
/* An opening date, under the "Not yet open" badge. It used to be a chip in a
   queue on another tab; a date belongs on the row of the state it opens. */
.ei-ev-tr__when { display: block; margin-top: .28rem; font-size: .71rem; color: var(--ei-muted); font-variant-numeric: tabular-nums; }
.ei-ev-tr__when.is-unknown { font-style: italic; }
.ei-ev-pct { display: block; font-weight: 700; color: var(--ei-heading); }
.ei-ev-meter { display: block; height: 5px; margin-top: .3rem; border-radius: 999px; background: var(--ei-surface-2); overflow: hidden; }
[data-theme="dark"] .ei-ev-meter { background: var(--ei-bg); }
.ei-ev-meter__fill { display: block; height: 100%; border-radius: 999px; background: var(--ei-navy); }

.ei-ev-tablefoot { padding: 1rem 1.35rem 1.2rem; border-top: 1px solid var(--ei-border); background: var(--ei-surface); }
[data-theme="dark"] .ei-ev-tablefoot { background: var(--ei-surface-2); }
.ei-ev-tablefoot__p { margin: .5rem 0 0; font-size: .82rem; line-height: 1.55; color: var(--ei-muted); max-width: 78ch; }

/* ==================================================================== */
/* THE STATE PANEL                                                      */
/* ==================================================================== */

.ei-ev-detail { display: grid; gap: 1.4rem; }
.ei-ev-detail__head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; }
.ei-ev-detail__titles { min-width: 0; }
.ei-ev-detail__title { margin: 0; font-size: clamp(1.25rem, 2.4vw, 1.6rem); font-weight: 800; letter-spacing: -.02em; color: var(--ei-heading); }
.ei-ev-detail__meta { margin: .25rem 0 0; font-size: .85rem; color: var(--ei-muted); }
.ei-ev-detail__note { margin: 0; font-size: .85rem; color: var(--ei-muted); padding: .6rem .8rem; background: var(--ei-surface); border-radius: var(--ei-radius); }
[data-theme="dark"] .ei-ev-detail__note { background: var(--ei-surface-2); }
/* The coverage banner: whatever is unusual about how this state publishes,
   stated at the top of its own page, before any figure. */
.ei-ev-detail__cov { margin: .5rem 0 0; font-size: .82rem; line-height: 1.55; color: var(--ei-muted); max-width: 80ch; }
.ei-ev-detail__cov strong { color: var(--ei-heading); }
.ei-ev-detail__cov.is-partial strong { color: var(--ei-red); }
.ei-ev-close {
	flex: 0 0 auto; border: 1px solid var(--ei-border); background: var(--ei-bg); color: var(--ei-heading);
	font: inherit; font-size: .82rem; font-weight: 600; padding: .35rem .9rem; border-radius: 999px; cursor: pointer;
}
[data-theme="dark"] .ei-ev-close { background: var(--ei-surface-2); }
.ei-ev-close:hover { border-color: var(--ei-navy); color: var(--ei-navy); }

.ei-ev-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem; }
@media (max-width: 720px) { .ei-ev-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.ei-ev-stat { display: flex; flex-direction: column; gap: .15rem; }
.ei-ev-stat__val { font-size: 1.35rem; font-weight: 800; color: var(--ei-heading); line-height: 1.1; font-variant-numeric: tabular-nums; }
.ei-ev-stat__lab { font-size: .76rem; color: var(--ei-muted); }

/* Mail vs in person, moved off the board where it read as a second party bar. */
.ei-ev-arrive .ei-ev-bar--method { height: 20px; margin-top: .2rem; }
.ei-ev-arrive .ei-ev-bar__legend { margin-top: .45rem; font-size: .78rem; }

/* THE MEASURED CHANGE — a count, and the only figure of its kind here. No bar:
   the page's four bar shapes each already mean one thing and a fifth would
   start eroding them. */
.ei-ev-shiftslot:empty { display: none; }
.ei-ev-shift {
	margin-top: var(--ei-ev-card-gap); padding: var(--ei-ev-card-pad-y) var(--ei-ev-card-pad-x);
	border: 1px solid var(--ei-border); border-radius: var(--ei-radius);
	background: var(--ei-surface);
}
[data-theme="dark"] .ei-ev-shift { background: var(--ei-surface-2); }
.ei-ev-shift__fig { display: flex; align-items: baseline; flex-wrap: wrap; gap: .2rem .7rem; }
.ei-ev-shift__v { font-size: 1.35rem; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; color: var(--ei-heading); }
.ei-ev-shift__v.is-dem { color: var(--ei-navy); }
.ei-ev-shift__v.is-rep { color: var(--ei-red); }
.ei-ev-shift__l { font-size: .82rem; font-weight: 600; color: var(--ei-heading); }
.ei-ev-shift__p { margin: .4rem 0 0; font-size: .82rem; line-height: 1.55; color: var(--ei-muted); max-width: 80ch; }

/* WHO SHOWED UP AGAINST WHO IS REGISTERED — .ei-ev-skew
   Two stacked partitions, which is the shape this page already uses for a
   reported split, and both rows here ARE reported splits. The deltas under them
   are text rather than a fifth bar shape, for the reason above. The block wraps
   an .ei-ev-shift, so the headline number needs no rules of its own. */
.ei-ev-skew {
	margin-top: var(--ei-ev-card-gap); padding: var(--ei-ev-card-pad-y) var(--ei-ev-card-pad-x);
	border: 1px solid var(--ei-border); border-radius: var(--ei-radius);
	background: var(--ei-surface);
}
[data-theme="dark"] .ei-ev-skew { background: var(--ei-surface-2); }
.ei-ev-skew__h { margin: 0 0 .1rem; font-size: .95rem; font-weight: 700; color: var(--ei-heading); }
.ei-ev-skew .ei-ev-shift { margin-top: var(--ei-ev-block-gap); padding: 0; border: 0; background: none; }
[data-theme="dark"] .ei-ev-skew .ei-ev-shift { background: none; }
.ei-ev-skew__rows { display: grid; gap: .5rem; margin-top: var(--ei-ev-block-gap); }
.ei-ev-skew__row { display: grid; grid-template-columns: minmax(0, 1fr); gap: .2rem; }
@media (min-width: 32rem) {
	.ei-ev-skew__row { grid-template-columns: 8.5rem minmax(0, 1fr); align-items: center; gap: .7rem; }
}
.ei-ev-skew__rowl { display: flex; align-items: baseline; gap: .4rem; font-size: .78rem; font-weight: 600; color: var(--ei-muted); }
.ei-ev-skew__cy { font-variant-numeric: tabular-nums; color: var(--ei-heading); }
.ei-ev-skew__row.is-returns { margin-top: .25rem; padding-top: .5rem; border-top: 1px dashed var(--ei-border); }
/* The prior cycle's returns at this point, one row above today's: same shape,
   dimmed, so it reads as the reference and not a second live count. It opens
   the returns group, so the dashed rule sits on it and not on today's row. */
.ei-ev-skew__row.is-prior { opacity: .62; }
/* "Returned ’24" stays on one line; the days-out note wraps beneath it rather
   than splitting the name around itself in the 8.5rem label column. */
.ei-ev-skew__row.is-prior .ei-ev-skew__rowl { flex-wrap: wrap; gap: 0 .4rem; }
.ei-ev-skew__row.is-prior .ei-ev-skew__cy { white-space: nowrap; }
.ei-ev-skew__row.is-prior .ei-ev-skew__d { font-weight: 500; }
@media (min-width: 32rem) {
	.ei-ev-skew__row.is-prior .ei-ev-skew__d { flex-basis: 100%; }
}
.ei-ev-skew__row.is-prior + .ei-ev-skew__row.is-returns { margin-top: 0; padding-top: 0; border-top: 0; }
.ei-ev-skew__cap { margin: .55rem 0 0; font-size: .74rem; line-height: 1.5; color: var(--ei-muted); }
.ei-ev-skew__deltas { display: flex; flex-wrap: wrap; gap: .25rem .9rem; margin-top: .7rem; font-size: .78rem; font-variant-numeric: tabular-nums; }
.ei-ev-skew__d { display: inline-flex; align-items: center; gap: .3rem; white-space: nowrap; color: var(--ei-muted); }
.ei-ev-skew__d.is-dem { color: var(--ei-navy); }
.ei-ev-skew__d.is-rep { color: var(--ei-red); }
.ei-ev-skew__d.is-ind { color: var(--ei-ind); }
.ei-ev-skew__d.is-oth { color: var(--ei-muted); }
.ei-ev-skew__src { margin: .8rem 0 0; font-size: .74rem; line-height: 1.5; color: var(--ei-muted); }
.ei-ev-skew__srclink { color: inherit; text-decoration: underline; text-underline-offset: 2px; }

.ei-ev-sub { margin-top: var(--ei-ev-card-gap); padding-top: var(--ei-ev-card-pad-y); border-top: 1px solid var(--ei-border); }
.ei-ev-counties { display: grid; gap: .3rem; margin-top: .7rem; }
.ei-ev-county { display: grid; grid-template-columns: minmax(0, 9rem) minmax(0, 1fr) 5rem; gap: .7rem; align-items: center; font-size: .85rem; }
.ei-ev-county__name { color: var(--ei-heading); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ei-ev-county__track { height: 8px; border-radius: 999px; background: var(--ei-surface-2); overflow: hidden; }
[data-theme="dark"] .ei-ev-county__track { background: var(--ei-bg); }
.ei-ev-county__fill { display: block; height: 100%; border-radius: 999px; background: var(--ei-navy); }
.ei-ev-county__val { text-align: right; color: var(--ei-muted); font-variant-numeric: tabular-nums; }

/* COUNTY BY COUNTY — .ei-ev-ctable
   A real table, because it is one: several comparable measures per county and a
   reader who wants to sort by any of them. Wide content scrolls INSIDE its own
   container — the panel itself must never scroll sideways. The ballots cell
   keeps the old list's bar, which is still the fastest way to read relative
   size, stacked over the figure rather than beside it so the column stays
   narrow enough for the comparison columns to fit. */
.ei-ev-ctable__scroll { margin-top: .7rem; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.ei-ev-ctable { width: 100%; border-collapse: collapse; font-size: .82rem; }
.ei-ev-ctable__th {
	position: sticky; top: 0; z-index: 1;
	padding: .3rem .55rem; text-align: left; white-space: nowrap;
	background: var(--ei-surface); border-bottom: 1px solid var(--ei-border);
}
[data-theme="dark"] .ei-ev-ctable__th { background: var(--ei-surface-2); }
.ei-ev-ctable__th.is-num { text-align: right; }
.ei-ev-ctable__sort {
	appearance: none; background: none; border: 0; padding: 0; cursor: pointer;
	font: inherit; font-weight: 600; color: var(--ei-muted); text-align: inherit;
}
.ei-ev-ctable__sort:hover { color: var(--ei-heading); text-decoration: underline; text-underline-offset: 2px; }
.ei-ev-ctable__sort.is-on { color: var(--ei-heading); }
.ei-ev-ctable__sort.is-on::after { content: ""; }
.ei-ev-ctable__th[aria-sort="descending"] .ei-ev-ctable__sort.is-on::after { content: " \2193"; }
.ei-ev-ctable__th[aria-sort="ascending"] .ei-ev-ctable__sort.is-on::after { content: " \2191"; }
.ei-ev-ctable__td { padding: .35rem .55rem; border-bottom: 1px solid var(--ei-border); vertical-align: middle; }
.ei-ev-ctable__td.is-num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ei-ev-ctable tbody tr:last-child .ei-ev-ctable__td { border-bottom: 0; }
.ei-ev-ctable__name { color: var(--ei-heading); font-weight: 600; }
.ei-ev-ctable__ballots { display: block; width: 6.5rem; margin-left: auto; }
.ei-ev-ctable__v { display: block; }
.ei-ev-ctable__ballots .ei-ev-county__track { display: block; height: 4px; margin-top: .18rem; }
.ei-ev-ctable__m { font-weight: 700; }
.ei-ev-ctable__m.is-dem { color: var(--ei-navy); }
.ei-ev-ctable__m.is-rep { color: var(--ei-red); }
.ei-ev-ctable__m.is-even { color: var(--ei-muted); }
.ei-ev-ctable__more {
	appearance: none; margin-top: .6rem; padding: .35rem .7rem; cursor: pointer;
	font: inherit; font-size: .78rem; font-weight: 600; color: var(--ei-heading);
	background: var(--ei-surface-2); border: 1px solid var(--ei-border); border-radius: 999px;
}
.ei-ev-ctable__more:hover { border-color: var(--ei-heading); }

.ei-ev-demo { margin-top: .9rem; }
.ei-ev-demo__h { margin: 0 0 .3rem; font-size: .84rem; font-weight: 700; color: var(--ei-heading); }
.ei-ev-demo__bar { display: flex; height: 14px; border-radius: 999px; overflow: hidden; background: var(--ei-surface-2); }
.ei-ev-demo__seg { display: block; height: 100%; }
/* Five categorical fills, from the page's own tokens rather than five literals
   repeated from another file: navy, the method pair, the independent purple and
   the neutral grey. A demographic bucket is not a party, so the ORDER is
   arbitrary and the colours are only there to be told apart. */
.ei-ev-demo__seg.is-n0, .ei-ev-demo__dot.is-n0 { background: var(--ei-navy); }
.ei-ev-demo__seg.is-n1, .ei-ev-demo__dot.is-n1 { background: var(--ei-ev-mail); }
.ei-ev-demo__seg.is-n2, .ei-ev-demo__dot.is-n2 { background: var(--ei-ev-inperson); }
.ei-ev-demo__seg.is-n3, .ei-ev-demo__dot.is-n3 { background: var(--ei-ind); }
.ei-ev-demo__seg.is-n4, .ei-ev-demo__dot.is-n4 { background: var(--ei-ev-oth); }

/* A state with no party registration: say so, don't draw an empty chart. */
.ei-ev-nopanel { padding: 1rem 1.1rem; border: 1px dashed var(--ei-border); border-radius: var(--ei-radius); background: var(--ei-surface); }
[data-theme="dark"] .ei-ev-nopanel { background: var(--ei-surface-2); }
.ei-ev-nopanel__p { margin: 0; font-size: .88rem; line-height: 1.55; color: var(--ei-muted); max-width: 72ch; }
/* Arizona's panel carries a second paragraph — why we will not MODEL it either,
   which is a separate argument from why it has no split. */
.ei-ev-nopanel__p + .ei-ev-nopanel__p { margin-top: .6rem; }

/* ==================================================================== */
/* THE THOUGHT EXPERIMENT — .ei-ev-what                                 */
/*                                                                      */
/* The one thing on this page published DESPITE its own measurement, and */
/* the only object here drawn with no fill and NO COLOUR. Every other    */
/* figure earns a hue: navy and red for a party, teal and ochre for a    */
/* method, graphite for the model, one solid party colour for a past     */
/* result. This gets none, on a dotted outline over the page's own       */
/* background — distinct by ABSENCE.                                     */
/*                                                                      */
/* ⚠️ IT WAS PROMOTED, ON REQUEST. It now sits at the TOP of the state    */
/* panel, above the 2024 benchmark, and its reading is the largest       */
/* figure in the panel — larger than .ei-ev-stat__val (1.35rem) and than */
/* the benchmark's own .ei-ev-past__v (1.5rem), which is the inversion   */
/* that was asked for. What it gained is SIZE AND POSITION.              */
/*                                                                      */
/* ⚠️ THE RULE CHANGED, ON REQUEST, AND IT IS NOW A LINE RATHER THAN A   */
/* BLANKET: VALUES TAKE COLOUR, UNCERTAINTY DOES NOT, AND THE CARD       */
/* ITSELF STAYS UNTINTED.                                                */
/*                                                                      */
/* What this card reports IS a margin, and every other margin on this    */
/* page is navy or red. A grey "R+4.9" beside a red "R+3.2" six lines    */
/* above it does not read as deliberate restraint; it reads as a broken  */
/* number. So the two FIGURES — the reading and the difference — take the */
/* hue the rest of the page uses, and the difference takes the direction */
/* it MOVED rather than the result's colour: a shift toward the          */
/* Democrats is navy even where the result stays red.                    */
/*                                                                      */
/* ⚠️ STILL NO FILL, NO TINT, NO SOLID BORDER, and the band, the scale   */
/* stick and their labels STAY GREY. The provisional signal was never    */
/* the greyness of a number — it is the dotted frame, the badge, and an  */
/* uncertainty bar visibly wider than the shift it brackets. Colouring   */
/* the uncertainty is what would make this look measured; colouring the  */
/* value only makes it legible.                                          */
/*                                                                      */
/* THE COMPOSITION: a narrow FIGURE RAIL and a wide CHART, side by side. */
/* The chart is the interesting object — a band far wider than the shift */
/* it brackets — so it gets the room, and the prose is two lines and a   */
/* link. Everything longer lives in the Info tab's methodology card.     */
/*                                                                      */
/* ⚠️ THE EMPTY STATE IS A DESIGNED STATE (.ei-ev-what.is-empty), not a   */
/* fallback. It is what this block looks like for most of the season, so */
/* it shares the card, the grid, the type scale and the CHART FRAME with */
/* the populated one — same axis, same size, same place — and the day a  */
/* reading lands nothing on the page moves.                              */
/* ==================================================================== */

.ei-ev-what {
	display: grid; gap: var(--ei-ev-block-gap);
	margin-top: var(--ei-ev-card-gap);
	padding: var(--ei-ev-card-pad-y) var(--ei-ev-card-pad-x);
	border: 2px dotted var(--ei-ev-what-edge);
	border-radius: var(--ei-radius);
	background: none;
}
.ei-ev-what__head { display: grid; gap: .4rem; }
/* The word is "Thought experiment" and it never changes. Dotted, like its card,
   and the first thing in the reading order for exactly that reason. */
.ei-ev-what__badge {
	justify-self: start;
	font-size: .66rem; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
	padding: .22rem .55rem; border-radius: 999px;
	color: var(--ei-muted); border: 1px dotted var(--ei-muted);
}
.ei-ev-what__title { margin: 0; font-size: 1.1rem; font-weight: 700; letter-spacing: -.01em; color: var(--ei-heading); }
.ei-ev-what__sub { margin: 0; font-size: .84rem; line-height: 1.55; color: var(--ei-muted); max-width: 74ch; }

/* --------------------------------------------------------- the composition */
.ei-ev-what__body { display: grid; gap: 1rem; align-items: start; }
@media (min-width: 780px) {
	.ei-ev-what__body {
		grid-template-columns: minmax(8.5rem, 11rem) minmax(0, 1fr);
		gap: 1.6rem;
	}
	/* A dotted hairline between the figures and the picture, matching the
	   card's own edge — the same rule the rest of the page draws between two
	   halves of one sentence, in this block's own language. */
	.ei-ev-what__figure {
		align-self: stretch;
		border-left: 1px dotted var(--ei-ev-what-edge);
		padding-left: 1.6rem;
	}
}

/* THE FIGURE RAIL. The MODELLED margin is the big one and the 2024 result
   below it is small: the model is meaningless without its anchor, but the
   anchor is the supporting number here, not the headline. */
.ei-ev-what__rail { display: grid; gap: .75rem; align-content: start; }
.ei-ev-what__hero { display: grid; gap: .2rem; }
.ei-ev-what__hv {
	font-size: clamp(2.1rem, 5vw, 2.8rem); font-weight: 800; line-height: .95;
	letter-spacing: -.04em; color: var(--ei-heading); font-variant-numeric: tabular-nums;
}
.ei-ev-what__hl { font-size: .78rem; line-height: 1.35; color: var(--ei-muted); }
/* VALUES TAKE COLOUR — see the rule at the top of this block. */
.ei-ev-what__hv.is-dem { color: var(--ei-navy); }
.ei-ev-what__hv.is-rep { color: var(--ei-red); }
.ei-ev-what__hv.is-even { color: var(--ei-heading); }
.ei-ev-what__v.is-dem { color: var(--ei-navy); }
.ei-ev-what__v.is-rep { color: var(--ei-red); }
.ei-ev-what__v.is-even { color: var(--ei-heading); }
/* No reading yet. The slot holds the WORDS "Not yet" rather than a dash: an em
   dash at this size is a thick bar and reads as a redaction. Muted and a size
   down, so the largest thing in the panel is not also the loudest — everything
   else in the block, the chart frame included, is identical to the populated
   state. Never a 0, never a 0%, never an "Even". */
.ei-ev-what.is-empty .ei-ev-what__hv {
	color: var(--ei-muted);
	font-size: clamp(1.55rem, 3.4vw, 2rem);
	letter-spacing: -.02em;
}
/* The two supporting figures, each under a dotted hairline so the rail reads
   as one column of related numbers rather than three loose blocks. */
.ei-ev-what__fig {
	display: grid; gap: .1rem;
	padding-top: .7rem; border-top: 1px dotted var(--ei-ev-what-edge);
}
/* Achromatic, including the margins: a party colour here would say "result". */
.ei-ev-what__v { font-size: 1.15rem; font-weight: 700; line-height: 1.1; color: var(--ei-heading); font-variant-numeric: tabular-nums; }
.ei-ev-what__l { font-size: .73rem; line-height: 1.35; color: var(--ei-muted); }

/* ------------------------------------------------------------ the chart */
/* ONE FRAME FOR BOTH STATES. The viewBox, the aspect ratio and the axis are
   identical whether there is a reading or not, so the empty state is the same
   object rather than a placeholder of another shape. */
/* The picture is vertically centred against the figure rail beside it, and the
   dotted divider still runs the full height of the pair — so the two columns
   read as one object rather than two stacks that happen to be adjacent. */
.ei-ev-what__figure { display: grid; gap: .75rem; min-width: 0; align-content: center; }
.ei-ev-what__chart { display: grid; gap: .4rem; }
.ei-ev-whatsvg { width: 100%; max-width: 720px; height: auto; aspect-ratio: 720 / 84; display: block; }
.ei-ev-whataxis { stroke: var(--ei-border); stroke-width: 1; }
.ei-ev-whatzero { stroke: var(--ei-ev-land-edge); stroke-width: 1; stroke-dasharray: 2 2; }
/* The band is drawn at the SAME SCALE as the shift, which is the argument: it
   is far wider than the movement it brackets. */
.ei-ev-whatband { stroke: var(--ei-muted); stroke-width: 2; opacity: .45; }
.ei-ev-whatcap { stroke: var(--ei-muted); stroke-width: 1.5; opacity: .45; }
/* Where the band actually reaches, in margin words, under its own ends. */
.ei-ev-whatbandlab { fill: var(--ei-muted); font-size: 10px; font-variant-numeric: tabular-nums; }
/* THE EMPTY STATE'S MEASURING STICK. ±11.5 points laid on the same axis the
   reading will use, so the argument is legible before there is a number to
   argue about. Dotted, and anchored at the axis ORIGIN rather than centred —
   the empty axis is centred on the state's own 2024 result, so a centred stick
   would sit exactly under that dot and read as an interval around it. */
.ei-ev-whatscale { stroke: var(--ei-muted); stroke-width: 2; stroke-dasharray: 3 3; opacity: .6; }
.ei-ev-whatscalecap { stroke: var(--ei-muted); stroke-width: 1.5; opacity: .6; }
.ei-ev-whatdot { stroke: var(--ei-heading); stroke-width: 1.6; }
.ei-ev-whatdot.is-actual { fill: var(--ei-heading); }
.ei-ev-whatdot.is-implied { fill: var(--ei-bg); }
[data-theme="dark"] .ei-ev-whatdot.is-implied { fill: var(--ei-surface); }
.ei-ev-whataxlab { fill: var(--ei-muted); font-size: 10px; font-style: italic; }
.ei-ev-what__key { display: flex; flex-wrap: wrap; gap: .25rem .9rem; font-size: .74rem; color: var(--ei-muted); }
.ei-ev-what__keyitem { display: inline-flex; align-items: center; gap: .35rem; }
.ei-ev-what__keymark { width: .6rem; height: .6rem; border-radius: 999px; border: 1.5px solid var(--ei-heading); flex: 0 0 auto; }
.ei-ev-what__keymark.is-actual { background: var(--ei-heading); }
.ei-ev-what__keymark.is-implied { background: transparent; }
.ei-ev-what__keymark.is-band { width: 1.4rem; height: 2px; border: 0; border-radius: 0; background: var(--ei-muted); opacity: .45; }
/* The two empty-state marks: the reading that is not there yet, and the width
   of the band it will carry. Dotted, matching the card's own edge, so the
   legend says "pending" in the same language the block says it in. */
.ei-ev-what__keymark.is-pending { background: transparent; border-style: dotted; border-color: var(--ei-muted); }
.ei-ev-what__keymark.is-ghost {
	width: 1.4rem; height: 0; border: 0; border-radius: 0; background: none;
	border-top: 2px dotted var(--ei-muted); align-self: center; opacity: .8;
}
/* The empty state's one line: what is missing, and when it arrives. A DOTTED
   rule, matching the card's edge — a statement about the block's readiness,
   not about its trustworthiness, so deliberately not the red one below. */
.ei-ev-what__pending {
	margin: 0; padding-left: .8rem;
	border-left: 3px dotted var(--ei-ev-what-edge);
	font-size: .81rem; line-height: 1.5; color: var(--ei-heading);
	max-width: 68ch;
}

/* ------------------------------------------------------------- the foot */
/* ONE calm accuracy line and the link to the full method. The measured
   figures behind the line — −0.10 points against the no-change null, ±11.5 of
   band, 1.2 against 11.1 — are not deleted; they are the Info tab's
   methodology card, which is where a reader who wants them will look. */
.ei-ev-what__foot {
	display: flex; flex-wrap: wrap; gap: .5rem 1.6rem;
	align-items: baseline; justify-content: space-between;
	padding-top: .85rem; border-top: 1px dotted var(--ei-ev-what-edge);
}
.ei-ev-what__err {
	margin: 0; flex: 1 1 26rem;
	font-size: .84rem; line-height: 1.5; color: var(--ei-muted); max-width: 74ch;
}
.ei-ev-what__more {
	flex: 0 0 auto; font-size: .8rem; font-weight: 700; white-space: nowrap;
	color: var(--ei-link); text-decoration: none;
	border-bottom: 1px dotted currentColor;
}
.ei-ev-what__more:hover, .ei-ev-what__more:focus-visible { border-bottom-style: solid; }

/* ==================================================================== */
/* THE MODELLED PARTY ESTIMATE — .ei-ev-est*                            */
/*                                                                      */
/*   REPORTED (.ei-fc-voteshare)      ESTIMATED (.ei-ev-est)            */
/*   solid card, 1px solid border     dashed 2px border, tinted card    */
/*   navy + red, fully saturated      neutral graphite — NOT a party    */
/*                                    colour, because this is not a     */
/*                                    party's number                    */
/*   a stacked bar: every pixel of    an interval on an axis: most of   */
/*   the track is filled and the      the track is empty, and the       */
/*   boundary between colours IS      empty part is the whole point     */
/*   the number                                                         */
/*   flat fills                       45° hatch, used nowhere else here */
/*                                                                      */
/* ⚠️ DO NOT give this block navy or red fills to "match the page". The  */
/* moment it matches the page it starts reading as a reported figure.   */
/* ==================================================================== */

/* The Overview no longer carries a card of them — a modelled state is a
   stippled shape on the map's modelled view there, with its range on hover —
   so this block is the state panel's, and the tooltip's. */
.ei-ev-est {
	margin-top: 1rem;
	padding: 1rem 1.1rem 1.05rem;
	display: grid;
	gap: .55rem;
	/* Dashed, and 2px. The one border treatment on the page that says
	   "provisional" before anything is read. */
	border: 2px dashed var(--ei-ev-est-border);
	border-radius: var(--ei-radius);
	background: var(--ei-ev-est-bg);
}
.ei-ev-est__head { display: flex; align-items: baseline; flex-wrap: wrap; gap: .45rem .6rem; }
/* The word on the badge is "Estimate" and it never changes. */
.ei-ev-est__badge {
	display: inline-flex; align-items: center; gap: .3rem;
	font-size: .64rem; font-weight: 800; letter-spacing: .09em; text-transform: uppercase;
	padding: .2rem .5rem; border-radius: 999px;
	color: var(--ei-ev-est-ink);
	background: var(--ei-bg);
	border: 1px dashed var(--ei-ev-est-border);
}
[data-theme="dark"] .ei-ev-est__badge { background: var(--ei-surface-2); }
.ei-ev-est__title { margin: 0; font-size: .92rem; font-weight: 700; color: var(--ei-heading); }
.ei-ev-est__sub { margin: 0; font-size: .82rem; line-height: 1.5; color: var(--ei-muted); max-width: 68ch; }

/* Figure left, caveats right — from 900px up. One column left two thirds of the
   card empty and pushed the measured-error note below the fold, which is the
   one paragraph on this card that must not be scrolled past. */
.ei-ev-est__body { display: grid; gap: .7rem 1.6rem; }
.ei-ev-est__figcol,
.ei-ev-est__notes { display: grid; gap: .55rem; align-content: start; }
@media (min-width: 900px) {
	.ei-ev-est:not(.is-compact) .ei-ev-est__body {
		grid-template-columns: minmax(280px, 420px) minmax(0, 1fr);
	}
}

/* THE RANGE IS THE HEADLINE, and the type sizes say so. Reversing these two is
   how a band turns back into a point estimate with a caveat. */
.ei-ev-est__figure { display: grid; gap: .05rem; margin: .1rem 0; }
.ei-ev-est__range {
	font-size: clamp(1.5rem, 3.6vw, 2rem); font-weight: 800; letter-spacing: -.02em;
	line-height: 1.05; color: var(--ei-ev-est-ink); font-variant-numeric: tabular-nums;
}
.ei-ev-est__rangelab { font-size: .76rem; font-weight: 600; color: var(--ei-muted); }
.ei-ev-est__mid { font-size: .74rem; color: var(--ei-muted); font-style: italic; }

.ei-ev-estsvg { width: 100%; max-width: 460px; height: auto; aspect-ratio: 420 / 62; display: block; }
.ei-ev-esttrack { fill: var(--ei-ev-est-track); }

/* THE BAND AT TABLE SCALE — .ei-ev-estmini / .ei-ev-estcell
   Same classes as the card's chart for everything inside the SVG, so a theme
   change cannot move one without the other. Only the box is different. */
.ei-ev-estmini { display: block; width: 100%; max-width: 8.5rem; height: 12px; }
.ei-ev-estcell { display: grid; gap: .22rem; justify-items: start; }
.ei-ev-td.is-past24, .ei-ev-th.is-past24 { min-width: 8.5rem; }
.ei-ev-td.is-cf24, .ei-ev-th.is-cf24 { min-width: 8rem; }
.ei-ev-cfcell { display: grid; gap: .1rem; }
.ei-ev-cfcell__m { font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ei-heading); }
.ei-ev-cfcell__m.is-dem { color: var(--ei-navy); }
.ei-ev-cfcell__m.is-rep { color: var(--ei-red); }
.ei-ev-cfcell__d { font-size: .72rem; color: var(--ei-muted); font-variant-numeric: tabular-nums; }
/* The estimate cell now carries the same two party keys the counted column
   does, so it needs the same tight legend rather than the card's spacing. */
.ei-ev-estcell .ei-ev-bar__legend { margin-top: 0; gap: .05rem .6rem; font-size: .7rem; }
.ei-ev-td.is-past24 .ei-ev-partybar { max-width: 8.5rem; }
.ei-ev-estcell__line { display: flex; align-items: center; flex-wrap: wrap; gap: .35rem; font-size: .72rem; }
.ei-ev-estcell__v { color: var(--ei-heading); font-weight: 600; font-variant-numeric: tabular-nums; }
.ei-ev-estcell__tag {
	padding: 0 .32rem; border-radius: 3px; text-transform: uppercase;
	font-size: .6rem; font-weight: 700; letter-spacing: .04em;
	color: var(--ei-ev-est-ink); background: var(--ei-ev-est-track);
	border: 1px solid var(--ei-ev-est-line);
}
.ei-ev-esthatch__bg { fill: none; }
.ei-ev-esthatch__line { stroke: var(--ei-ev-est-line); stroke-width: 2.2; opacity: .55; }
.ei-ev-estband__edge { fill: none; stroke: var(--ei-ev-est-line); stroke-width: 1; }
/* The 50–50 line: the only fixed reference on this chart. */
.ei-ev-estmid { stroke: var(--ei-heading); stroke-width: 1; opacity: .45; }
/* The central estimate. A tick INSIDE the band, never a boundary between two
   filled colours — that shape is what a reported split looks like. */
.ei-ev-esttick { stroke: var(--ei-ev-est-ink); stroke-width: 2.5; stroke-linecap: round; }
.ei-ev-estbase { fill: var(--ei-heading); opacity: .55; }
.ei-ev-estaxis { fill: var(--ei-muted); font-size: 9.5px; font-style: italic; }
.ei-ev-estaxis.is-mid { font-style: normal; letter-spacing: .04em; }

.ei-ev-est__basenote { margin: -.2rem 0 0; font-size: .74rem; color: var(--ei-muted); }
/* THE MEASURED ERROR. Body size, not caption size, on the same red rule
   .ei-ev-caution uses. A reader who sees the number has to see this. Never
   shrink it. */
.ei-ev-est__err {
	margin: .25rem 0 0; padding-left: .8rem;
	border-left: 3px solid var(--ei-red);
	font-size: .84rem; line-height: 1.55; font-weight: 600; color: var(--ei-heading);
	max-width: 78ch;
}
/* The one statement the geography actually supports. Kept visually apart from
   the estimate so it does not read as a caveat on it. */
.ei-ev-est__lean {
	margin: 0; padding: .55rem .7rem; border-radius: calc(var(--ei-radius) - 4px);
	background: var(--ei-bg); border: 1px solid var(--ei-border);
	font-size: .82rem; line-height: 1.5; color: var(--ei-heading); max-width: 76ch;
}
[data-theme="dark"] .ei-ev-est__lean { background: var(--ei-surface-2); }
.ei-ev-est__lean strong { color: var(--ei-ev-est-ink); }
.ei-ev-est__meta { margin: 0; font-size: .74rem; color: var(--ei-muted); font-variant-numeric: tabular-nums; }
.ei-ev-est__caption { margin: 0; font-size: .78rem; line-height: 1.5; color: var(--ei-muted); max-width: 78ch; }
.ei-ev-est__link { font-size: .8rem; font-weight: 700; color: var(--ei-navy); text-decoration: none; justify-self: start; }
.ei-ev-est__link:hover { text-decoration: underline; }
[data-theme="dark"] .ei-ev-est__link { color: var(--ei-link); }

/* Compact: the Overview draws one per state, so the shared prose is printed
   once for the whole card instead of N times inside it. */
.ei-ev-est.is-compact { margin-top: 0; padding: .8rem .9rem; gap: .4rem; }
.ei-ev-est.is-compact .ei-ev-est__range { font-size: 1.3rem; }
.ei-ev-est.is-compact .ei-ev-est__err,
.ei-ev-est.is-compact .ei-ev-est__caption { display: none; }
.ei-ev-est.is-compact .ei-ev-estsvg { max-width: none; }

/* ==================================================================== */
/* CHARTS — shared by the Overview curve and the state panel            */
/* ==================================================================== */

.ei-ev-chart { min-width: 0; }
.ei-ev-chart__title { margin: 0 0 .2rem; font-size: .98rem; font-weight: 700; color: var(--ei-heading); }
.ei-ev-chart__sub { margin: 0 0 .7rem; font-size: .82rem; line-height: 1.5; color: var(--ei-muted); max-width: 72ch; }
.ei-ev-svg { width: 100%; height: auto; aspect-ratio: 860 / 300; display: block; overflow: visible; }
.ei-ev-gridline { stroke: var(--ei-border); stroke-width: 1; }
.ei-ev-axistext { fill: var(--ei-muted); font-size: 11px; font-variant-numeric: tabular-nums; }
.ei-ev-axislab { fill: var(--ei-muted); font-size: 10px; font-style: italic; }
.ei-ev-line { fill: none; stroke-width: 2.6; stroke-linejoin: round; stroke-linecap: round; }
.ei-ev-line.is-2026 { stroke: var(--ei-navy); }
.ei-ev-line.is-2022 { stroke: var(--ei-ev-2022); stroke-width: 1.8; stroke-dasharray: 7 4; }
.ei-ev-line.is-2024 { stroke: var(--ei-ev-2024); stroke-width: 1.8; stroke-dasharray: 2 3; }
.ei-ev-dot.is-2026 { fill: var(--ei-navy); stroke: var(--ei-bg); stroke-width: 2; }
.ei-ev-bar2 { fill: var(--ei-navy); opacity: .85; }
.ei-ev-bar2:hover { opacity: 1; }
.ei-ev-bar2.is-restated { fill: var(--ei-ev-inperson); }
.ei-ev-area.is-dem { fill: var(--ei-navy); }
.ei-ev-area.is-rep { fill: var(--ei-red); }
.ei-ev-area.is-ind { fill: var(--ei-ind); }
.ei-ev-area.is-oth { fill: var(--ei-ev-oth); }

/* ONE .ei-ev-legend rule. There were two, three hundred lines apart, and the
   second silently overrode half of the first — which is how a chart legend and
   a map legend ended up with the same class and different gaps. */
.ei-ev-legend {
	display: flex; flex-wrap: wrap; align-items: center;
	gap: .35rem 1rem; margin-top: .5rem; font-size: .78rem; color: var(--ei-muted);
}
.ei-ev-legend__key { display: inline-flex; align-items: center; gap: .35rem; }
.ei-ev-legend__line { width: 20px; height: 0; border-top-width: 2.6px; border-top-style: solid; }
.ei-ev-legend__line.is-2026 { border-color: var(--ei-navy); }
.ei-ev-legend__line.is-2022 { border-color: var(--ei-ev-2022); border-top-style: dashed; border-top-width: 2px; }
.ei-ev-legend__line.is-2024 { border-color: var(--ei-ev-2024); border-top-style: dotted; border-top-width: 2px; }

.ei-ev-chartwrap--hover { position: relative; }
.ei-ev-guide { stroke: var(--ei-border); stroke-width: 1; pointer-events: none; }
.ei-ev-hoverdot { pointer-events: none; stroke: var(--ei-bg); stroke-width: 2; }
.ei-ev-hoverdot.is-2026, .ei-ev-hoverdot.is-dem { fill: var(--ei-navy); }
.ei-ev-hoverdot.is-2022 { fill: var(--ei-ev-2022); }
.ei-ev-hoverdot.is-2024 { fill: var(--ei-ev-2024); }
.ei-ev-hoverdot.is-rep { fill: var(--ei-red); }
.ei-ev-hoverdot.is-ind { fill: var(--ei-ind); }
.ei-ev-hoverdot.is-oth { fill: var(--ei-ev-oth); }

.ei-ev-charttip {
	position: absolute; top: .3rem; z-index: 6; pointer-events: none;
	transform: translateX(-50%);
	background: var(--ei-heading); color: var(--ei-surface);
	border-radius: 8px; padding: .45rem .6rem;
	font-size: .76rem; line-height: 1.35; white-space: nowrap;
	display: grid; gap: .12rem;
	box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
}
.ei-ev-charttip__h { font-weight: 800; margin-bottom: .1rem; }
.ei-ev-charttip__row { display: grid; grid-template-columns: auto 1fr auto; gap: .4rem; align-items: center; }
.ei-ev-charttip__val { font-weight: 700; font-variant-numeric: tabular-nums; }
.ei-ev-charttip__key { width: .5rem; height: .5rem; border-radius: 2px; background: currentColor; }
.ei-ev-charttip__key.is-2022 { background: var(--ei-ev-2022); }
.ei-ev-charttip__key.is-2024 { background: var(--ei-ev-2024); }
/* Both tooltips sit on a dark ground in both themes, so they share ONE set of
   lifted party keys rather than two copies of four hex literals. */
.ei-ev-charttip__key.is-2026, .ei-ev-charttip__key.is-dem, .ei-ev-tip__key.is-dem { background: var(--ei-ev-tip-dem); }
.ei-ev-charttip__key.is-rep, .ei-ev-tip__key.is-rep { background: var(--ei-ev-tip-rep); }
.ei-ev-charttip__key.is-ind, .ei-ev-tip__key.is-ind { background: var(--ei-ev-tip-ind); }
.ei-ev-charttip__key.is-oth, .ei-ev-tip__key.is-oth { background: var(--ei-ev-tip-oth); }

/* ==================================================================== */
/* MAPS                                                                 */
/*                                                                      */
/* The palette carries the same meaning as the rest of the page, and    */
/* ABSENCE IS NEVER WHITE: a white state on a choropleth reads as zero, */
/* and "has not opened yet" is not zero.                                */
/* ==================================================================== */

/* NOT overflow:hidden — the hover tooltip sits above the map and near the top
   edge it would be clipped away by the card. */
.ei-ev-mapcard { padding: 0; }
.ei-ev-maphead { padding: 1.15rem 1.35rem 1rem; border-bottom: 1px solid var(--ei-border); }
.ei-ev-maphead .ei-ev-cardhead { margin: 0 0 .85rem; padding-bottom: 0; border-bottom: 0; }

/* ONE control row, two groups, a hairline between them: what is shaded on the
   left, at what resolution on the right. They used to be two stacked rows with
   nothing to say which was which, and the second was quieted to signal it was
   secondary — which reads as disabled rather than as subordinate. */
.ei-ev-mapctl { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .9rem; }
.ei-ev-mapctl > * + *:not(:empty) {
	padding-left: .9rem; border-left: 1px solid var(--ei-border);
}
.ei-ev-modes { display: flex; flex-wrap: wrap; gap: .4rem; }
.ei-ev-mode {
	font: inherit; font-size: .8rem; font-weight: 700; cursor: pointer;
	padding: .35rem .75rem; border-radius: 999px;
	border: 1px solid var(--ei-border); background: var(--ei-surface);
	color: var(--ei-muted); transition: background .12s ease, color .12s ease;
}
[data-theme="dark"] .ei-ev-mode { background: var(--ei-surface-2); }
.ei-ev-mode:hover { color: var(--ei-heading); }
.ei-ev-mode:focus-visible { outline: 2px solid var(--ei-navy); outline-offset: 2px; }
.ei-ev-mode[aria-pressed="true"] { background: var(--ei-navy); border-color: var(--ei-navy); color: #fff; }
/* "By county" under the modelled view: there is no county model, so the pill is
   disabled rather than hidden — hiding it would move the row under the cursor.
   Quieted enough to read as unavailable, not merely secondary. */
.ei-ev-mode:disabled { opacity: .45; cursor: not-allowed; }
.ei-ev-mode:disabled:hover { color: var(--ei-muted); }
.ei-ev-levelhost:empty { display: none; }

/* Capped by WIDTH, not height: the Albers frame is 975x610, so a width cap sets
   the height without letterboxing or distorting. Uncapped, the map is ~775px
   tall on a desktop card and swallows the page whose headline is one integer. */
.ei-ev-mapfig {
	position: relative;
	padding: 1rem 1.35rem 0;
	max-width: 900px;
	margin: 0 auto;
}
/* The svg lives in its own canvas so swapping detail level cannot clear away
   the hover tooltip, which is a sibling of the canvas, not a child. */
.ei-ev-mapcanvas { display: block; }
.ei-ev-map {
	display: block;
	width: 100%;
	height: auto;
	/* Tall states (Florida, Maine, California) are near-square or taller once
	   fitted to their own bounds, so width alone would render them most of a
	   screen high. The SVG's default preserveAspectRatio letterboxes the drawing
	   inside the capped box and centres it, so nothing is cropped or squashed. */
	max-height: 540px;
}

.ei-ev-mapst {
	/* ⚠️ THE BASE FILL IS A SAFETY NET, NOT A DEFAULT.
	   SVG's initial `fill` is BLACK, so a shape whose modifier class has no rule
	   does not render "unstyled" -- it paints solid black, louder than any state
	   actually reporting. That has happened four times on this page (.is-never,
	   .is-nocounty, .ei-ev-partialmask, .ei-ev-badge--partial), every time
	   because a class was written in JS and never given a rule.
	   Declaring the neutral land colour HERE makes the worst case for a future
	   unstyled modifier "looks like every other quiet state" rather than a black
	   hole. Every real modifier below still overrides it. The companion guard is
	   tests/unstyled-classes.test.mjs, which fails when a class is emitted
	   without a rule; this keeps the page honest in the meantime. */
	fill: var(--ei-ev-land);
	/* A real line, not the card colour. White borders look crisp BETWEEN filled
	   states but make the country's outer edge vanish into the card, which is
	   most of why the light-mode map read as empty. */
	stroke: var(--ei-ev-land-edge);
	stroke-width: 0.7;
	stroke-linejoin: round;
	transition: opacity .12s ease;
	/* Stroke width is in USER UNITS, and the two maps have wildly different
	   ones: the national frame is 975 units wide, a single-state county frame
	   about 8. Without this, the same 0.7 is a hairline nationally and twelve
	   percent of the map's width in a state — wide enough that the strokes paint
	   over every county and the map renders blank. */
	vector-effect: non-scaling-stroke;
	/* `all`, not the default `visiblePainted`. A hatch-filled shape is painted
	   with a pattern that is mostly TRANSPARENT, and visiblePainted ignores the
	   gaps — so hovering a hatched county landed in a hole between stripes and
	   hit nothing at all. */
	pointer-events: all;
}
.ei-ev-mapst[role="button"] { cursor: pointer; }
.ei-ev-mapst[role="button"]:hover { opacity: .78; }
.ei-ev-mapst:focus-visible { outline: none; stroke: var(--ei-heading); stroke-width: 2; }

/* Open, reporting, coloured by the active mode (fill set inline). */
.ei-ev-mapst.is-value { fill: var(--ei-ev-land); }
/* Tracked, but early voting has NOT started. Flat neutral, clearly alive. */
.ei-ev-mapst.is-pending { fill: var(--ei-ev-land); }
/* ⚠️ `nocounty` HAD NO RULE AT ALL, which is not a cosmetic bug: an SVG path
   with no fill declared falls back to BLACK. Every county outside Texas's
   published report, and every county of a statewide-only state, rendered as a
   solid black shape on the national county map — louder than any state that was
   actually reporting. It is the same failure New Hampshire's `never` had before
   it was given the hatch. It takes the plain land tone: there IS a real figure
   for these places, it simply is not broken down this far. */
.ei-ev-mapst.is-nocounty { fill: color-mix(in srgb, var(--ei-ev-land) 55%, var(--ei-bg)); }
/* Nothing to say here: not tracked, or no party registration in party mode.
   `never` (a state that publishes nothing machine-readable) shares the hatch
   with `untracked`, because to a reader they are the same fact: no number is
   coming from here. */
.ei-ev-mapst.is-untracked,
.ei-ev-mapst.is-never,
.ei-ev-mapst.is-noparty { fill: url(#ei-ev-hatch); }
.ei-ev-hatchline { fill: var(--ei-ev-hatch); }

/* THE PARTIAL-COVERAGE OVERLAY — the only mark on this map that means "there
   IS a number here and it does not cover the whole shape". It rides ON TOP of
   the volume colour rather than replacing it, because replacing it would file a
   reporting state with the blank ones; the hatch tile is mostly transparent, so
   the fill underneath still reads.
   ⚠️ It had NO RULE AT ALL, which is the same latent failure `is-nocounty` had:
   an SVG path with no declared fill paints BLACK. It never showed because the
   only partial state has been reaching us at tier 3, where isPartial() is
   false — the first tier-1 Texas reading would have painted Texas solid black
   over the top of its own figure. */
.ei-ev-partialmask {
	fill: url(#ei-ev-hatch);
	stroke: var(--ei-red);
	stroke-width: 1.2;
	stroke-linejoin: round;
	vector-effect: non-scaling-stroke;
	pointer-events: none;
}

/* ==================================================================== */
/* THE MARK THAT MEANS "MODELLED" — on the counted map's modelled view    */
/* and on the Members' inferred map (.ei-ev-infmap) alike.               */
/*                                                                      */
/* A ramp across forty counted shapes is one uniform statement. A view   */
/* that mixes kinds — some shapes a state's own reported registration,   */
/* some a model — will happily let a reader take all of them as the same */
/* claim, which would undo the distinction the whole page is built on,   */
/* so the modelled ones are marked ON THE MAP, not in a tooltip.         */
/*                                                                      */
/*   counted     flat fill off the diverging ramp. Solid ground.         */
/*   MODELLED    the same fill under a DOT SCREEN, with a dashed edge.   */
/*               The colour still reads, so the value is still           */
/*               comparable; the surface is visibly broken up, which is  */
/*               the argument.                                           */
/*   nothing     the hatch, exactly as everywhere else here.             */
/*                                                                      */
/* ⚠️ THE HATCH ALREADY MEANS "no number is coming from here" and may     */
/* never be reused for "modelled". These are deliberately different      */
/* TEXTURES, not two weights of one: 45° lines against an orthogonal dot */
/* grid, so they do not read as variants of each other at a glance.      */
/* ==================================================================== */

.ei-ev-stippledot { fill: var(--ei-ev-hatch); }
.ei-ev-modelmask {
	fill: url(#ei-ev-stipple);
	stroke: var(--ei-ev-hatch);
	stroke-width: 1.1;
	stroke-dasharray: 3 2.5;
	stroke-linejoin: round;
	vector-effect: non-scaling-stroke;
	pointer-events: none;
}
/* The shape underneath keeps its ramp colour — the value must stay comparable —
   and takes a slightly stronger edge. The DASHES live on the overlay above it,
   which is drawn after every state, because a stroke drawn with the shape gets
   half painted over by whichever neighbour is drawn next. Same reason
   .ei-ev-partialmask carries its own red edge. */
.ei-ev-mapst.is-modelled { stroke: var(--ei-ev-hatch); }
/* "The comparison this needs cannot be made here yet." A THIRD thing, distinct
   from `pending` (has not opened) and from the hatch (nothing is coming): the
   state is open and counting, we simply have nothing to infer from yet. Lighter
   than the land so it reads as awaiting rather than as absent. */
.ei-ev-mapst.is-noreading { fill: color-mix(in srgb, var(--ei-ev-land) 25%, var(--ei-bg)); }

/* The legend has to NAME the stipple. A texture a reader must hover to decode
   is decoration, not a distinction. */
.ei-ev-legend__sw.is-counted,
.ei-ev-legend__item.is-counted .ei-ev-legend__sw { background: var(--ei-navy); border-color: var(--ei-navy); }
/* The legend's own modelled swatch on the COUNTED map, where `swatch()` builds
   a plain square and the modifier has to carry the texture itself. */
.ei-ev-legend__item.is-modelled .ei-ev-legend__sw {
	background: var(--ei-ev-land);
	background-image: radial-gradient(var(--ei-ev-hatch) 1.1px, transparent 1.2px);
	background-size: 5px 5px;
	border-style: dashed;
	border-color: var(--ei-ev-hatch);
}
.ei-ev-legend__sw.is-modelled {
	background:
		radial-gradient(var(--ei-ev-hatch) 34%, transparent 36%) 0 0 / 5px 5px,
		var(--ei-navy);
	border-style: dashed; border-color: var(--ei-ev-hatch);
}
.ei-ev-legend__sw.is-noreading { background: color-mix(in srgb, var(--ei-ev-land) 25%, var(--ei-bg)); }
.ei-ev-legend__sw.is-pending { background: var(--ei-ev-land); }
.ei-ev-legend__sw.is-hatch {
	background: repeating-linear-gradient(45deg, var(--ei-ev-hatch) 0 2px, transparent 2px 6px);
}

/* The inferred map's empty state. Every mode on it is empty until the first
   like-for-like window opens, so a blank map gets a written line rather than
   being left to read as a page that failed to load. Dotted, like every other "not yet" on
   this page. */
.ei-ev-infmap__empty {
	margin: 0 1.35rem .3rem; padding: .7rem .85rem;
	border: 1px dotted var(--ei-ev-what-edge); border-radius: var(--ei-radius);
	font-size: .82rem; line-height: 1.5; color: var(--ei-heading); max-width: 78ch;
}

/* County borders and the country edge, drawn OVER the county fills. Without
   them 3,142 pale shapes read as noise rather than a map. */
.ei-ev-mapline {
	fill: none;
	stroke: var(--ei-ev-land-edge);
	stroke-width: 0.8;
	stroke-linejoin: round;
	vector-effect: non-scaling-stroke;
	pointer-events: none;
}
.ei-ev-mapline.is-nation { stroke-width: 1.4; }
/* At county resolution the individual shapes are small, so the dividing lines
   between them have to get out of the way. */
.ei-ev-mapfig--national-counties .ei-ev-mapst { stroke-width: 0.25; }

.ei-ev-legendhost { padding: .5rem 1.35rem 0; }
.ei-ev-legend__item { display: inline-flex; align-items: center; gap: .35rem; font-size: .76rem; color: var(--ei-muted); }
.ei-ev-legend__sw {
	width: .8rem; height: .8rem; border-radius: 3px; flex: 0 0 auto;
	background: var(--ei-surface-2); border: 1px solid var(--ei-ev-land-edge);
}
.ei-ev-legend__item.is-pending .ei-ev-legend__sw { background: var(--ei-ev-land); }
.ei-ev-legend__item.is-nocounty .ei-ev-legend__sw { background: color-mix(in srgb, var(--ei-ev-land) 55%, var(--ei-bg)); }
.ei-ev-legend__item.is-hatch .ei-ev-legend__sw {
	background: repeating-linear-gradient(45deg, var(--ei-ev-hatch) 0 2px, transparent 2px 6px);
}
/* Party and volume ramps: one continuous bar, because the scale is continuous.
   Three swatches implied three buckets. */
.ei-ev-legend__item.is-ramp { gap: .4rem; }
.ei-ev-legend__ramp {
	display: inline-block; width: 160px; height: .55rem; border-radius: 999px;
	border: 1px solid var(--ei-border);
}
.ei-ev-legend__end { font-size: .7rem; font-weight: 700; color: var(--ei-muted); }

.ei-ev-mapnote {
	margin: 0; padding: .7rem 1.35rem 1.15rem;
	font-size: .78rem; line-height: 1.5; color: var(--ei-muted); max-width: 82ch;
}

/* The county map's slot inside the state card, above the charts. */
.ei-ev-mapslot { margin: 0; }
.ei-ev-mapslot:empty { display: none; }
/* The NATIONAL map's slot in the Overview — its own class, not .ei-ev-mapslot,
   because that one strips the card chrome off the per-state county map and the
   national map wants to keep it. Collapses when empty (pre-season, no feed). */
.ei-ev-natmapslot { margin: 0; }
.ei-ev-natmapslot:empty { display: none; }
/* Inside the detail card the map is already framed, so it drops the card chrome
   it carries when it stands alone. */
.ei-ev-mapslot .ei-ev-countycard { background: none; border: 0; box-shadow: none; padding: 0; }
.ei-ev-mapslot .ei-ev-maphead { padding: 0 0 .8rem; }

/* ONE structured map tooltip: title, subtitle, headline, label/value rows,
   footer. It was declared twice, two hundred lines apart. */
.ei-ev-tip {
	position: absolute; z-index: 5; pointer-events: none;
	transform: translate(-50%, calc(-100% - 10px));
	background: var(--ei-heading); color: var(--ei-surface);
	border-radius: 7px; padding: .35rem .55rem;
	font-size: .76rem; line-height: 1.25;
	text-align: left; min-width: 150px;
	/* Short rows stay on one line, but the box itself is capped and wraps rather
	   than running off the viewport. `nowrap` alone let one long footer push the
	   tip clean off the right of the screen. */
	white-space: normal;
	max-width: min(320px, 78vw);
	display: grid; gap: .05rem;
	box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
}
.ei-ev-tip strong { font-weight: 800; }
/* Flipped below the cursor when there is no room above (near the map's top
   edge), so the tip never runs off the card. */
.ei-ev-tip.is-below { transform: translate(-50%, 0); }
.ei-ev-tip__t { font-weight: 800; font-size: .8rem; }
.ei-ev-tip__sub { font-size: .68rem; opacity: .68; margin-top: -.1rem; }
.ei-ev-tip__lead { font-size: .82rem; font-weight: 700; margin: .18rem 0 .1rem; }
.ei-ev-tip__row {
	display: grid; grid-template-columns: auto 1fr auto; gap: .4rem;
	align-items: center; font-size: .72rem; white-space: nowrap;
}
.ei-ev-tip__key { width: .45rem; height: .45rem; border-radius: 2px; background: currentColor; }
.ei-ev-tip__lab { opacity: .72; }
.ei-ev-tip__val { font-weight: 700; font-variant-numeric: tabular-nums; }
.ei-ev-tip__foot {
	font-size: .66rem; opacity: .6; margin-top: .22rem;
	padding-top: .22rem; border-top: 1px solid rgba(255, 255, 255, .16);
}
/* THE ESTIMATE BLOCK — a different KIND of answer inside the same tooltip.
   A modelled figure set in the same type as a counted one, one hover apart, is
   the easiest way there is to launder a model into a measurement. So it is a
   dashed box carrying the word "Estimate" and a RANGE rather than a point,
   which is the same three moves .ei-ev-est makes, in the same vocabulary. */
.ei-ev-tip__est {
	display: grid; gap: .12rem; margin-top: .3rem;
	padding: .3rem .4rem;
	border: 1px dashed rgba(255, 255, 255, .38); border-radius: 5px;
}
.ei-ev-tip__esth { display: flex; align-items: center; gap: .35rem; flex-wrap: wrap; }
.ei-ev-tip__estbadge {
	font-size: .58rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
	padding: .05rem .3rem; border-radius: 999px;
	border: 1px dashed rgba(255, 255, 255, .5); opacity: .9;
}
.ei-ev-tip__estlab { font-size: .66rem; opacity: .72; }
/* The RANGE is the headline, never the midpoint. */
.ei-ev-tip__estval { font-size: .84rem; font-weight: 800; font-variant-numeric: tabular-nums; }
.ei-ev-tip__estnote { font-size: .63rem; opacity: .62; line-height: 1.35; }

/* ==================================================================== */
/* EMPTY STATES                                                         */
/* ==================================================================== */

.ei-ev-empty { text-align: left; }
.ei-ev-empty__title { margin: 0 0 .4rem; font-size: 1.05rem; font-weight: 800; color: var(--ei-heading); }
.ei-ev-empty__p { margin: 0; font-size: .92rem; line-height: 1.6; color: var(--ei-text); max-width: 70ch; }
.ei-ev-empty__meta { margin: .7rem 0 0; font-size: .84rem; color: var(--ei-muted); max-width: 70ch; }

/* ==================================================================== */
/* THE STANDING "this is a count, not a forecast" NOTICE                */
/*                                                                      */
/* Sits between the support band and the tab switcher, so it is read     */
/* before any view is chosen. Deliberately quieter than a warning        */
/* banner — it is a standing clarification, not an error — but with      */
/* enough weight that it is not skimmed past.                            */
/* ==================================================================== */

/* The support band carries a 24px drop shadow meant to lift it off a page
   background. Here the notice sits directly beneath it, so that shadow lands ON
   the notice and reads as a grey smudge along its top edge rather than as
   depth. Scoped by body class, so every other page keeps its shadow. */
.ei-page-early-vote .ei-support-band--deck { box-shadow: none; }

/* The SAME horizontal margins as .ei-support-band--deck directly above it, so
   the two read as one stacked pair rather than two cards of different widths. */
.ei-ev-notice {
	margin: clamp(.5rem, 1.2vw, .85rem) clamp(1rem, 4vw, 3rem) 0;
	padding: .7rem 1.15rem;
	display: flex; align-items: center; justify-content: center; gap: .55rem;
	border: 1px solid var(--ei-border);
	border-radius: 14px;
	background: var(--ei-surface);
}
.ei-ev-notice__mark { flex: 0 0 auto; color: var(--ei-navy); line-height: 0; }
.ei-ev-notice__mark svg { width: 16px; height: 16px; }
.ei-ev-notice__text { margin: 0; font-size: .85rem; line-height: 1.5; color: var(--ei-muted); text-align: center; }
.ei-ev-notice__text strong { color: var(--ei-heading); font-weight: 800; }
/* One line where there is room; wraps rather than overflows when there is not. */
@media (min-width: 900px) { .ei-ev-notice__text { white-space: nowrap; } }

/* ==================================================================== */
/* INFO TAB                                                             */
/*                                                                      */
/* Built from EXISTING house furniture rather than a fourth set of info  */
/* styles: the cards and headings are .ei-fc-info__* (global in          */
/* style.css) and the credits are the simulator's .ei-sim-crs blocks.    */
/* Only the two tables and the coverage list are local.                  */
/* ==================================================================== */

/* The source and error tables scroll inside their card rather than pushing the
   card wide — four columns of state names do not fit a phone. */
.ei-ev-infowrap { margin: .9rem 0 .2rem; }
.ei-ev-infotable { width: 100%; min-width: 620px; border-collapse: collapse; margin: .9rem 0 .2rem; font-size: .86rem; }
.ei-ev-infotable .ei-ev-th {
	text-align: left; padding: .5rem .75rem; font-size: .72rem; letter-spacing: .06em;
	text-transform: uppercase; color: var(--ei-muted); border-bottom: 1px solid var(--ei-border);
}

/* WHAT EACH SOURCE DOES AND DOES NOT COVER — and the only place on this page
   where a state that publishes nothing is explained at length. A ruled list
   rather than a run of paragraphs: each entry is one state, and the rule down
   the left is what stops five caveats reading as one wall of prose. */
.ei-ev-cov { list-style: none; margin: .9rem 0 .2rem; padding: 0; display: grid; gap: .95rem; }
.ei-ev-cov__item { padding-left: .85rem; border-left: 3px solid var(--ei-border); }
.ei-ev-cov__item.is-partial { border-left-color: var(--ei-red); }
.ei-ev-cov__item.is-none { border-left-color: var(--ei-muted); border-left-style: dashed; }
.ei-ev-cov__item.is-statewide { border-left-color: var(--ei-navy); }
.ei-ev-cov__head { margin: 0 0 .25rem; display: flex; flex-wrap: wrap; align-items: baseline; gap: .4rem .55rem; }
.ei-ev-cov__st { font-weight: 800; font-size: .95rem; color: var(--ei-heading); }
/* Same badge component the board uses, so the reader meets the same chip in
   both places rather than two designs for one label. */
.ei-ev-cov__badge { align-self: center; }
.ei-ev-cov__short { font-size: .8rem; font-style: italic; color: var(--ei-muted); }
.ei-ev-cov__note { margin: 0; font-size: .86rem; line-height: 1.6; color: var(--ei-muted); max-width: 74ch; }

/* The Info tab's error table. .ei-ev-table gives it the page's table skin;
   these only add the numeric alignment and the emphasis. */
.ei-ev-errtable .ei-ev-td.is-num,
.ei-ev-errtable .ei-ev-th.is-num { text-align: right; font-variant-numeric: tabular-nums; }
.ei-ev-errtable .is-err { font-weight: 700; color: var(--ei-heading); }
/* The model this page used to publish. Quieted, because the column is there to
   be compared against rather than read on its own. */
.ei-ev-errtable .is-was { color: var(--ei-muted); }
/* "North Carolina 2022" wrapping to three lines made every row three rows tall
   and the table twice the height of the argument it is making. */
.ei-ev-errtable .is-series { white-space: nowrap; }
/* Seven numeric columns at the shared cell padding overflow the Info card by a
   handful of pixels, which puts the last column — the one the whole table
   exists to make a point about — behind a scrollbar. */
.ei-ev-errtable .ei-ev-td,
.ei-ev-errtable .ei-ev-th { padding-left: .4rem; padding-right: .4rem; font-size: .79rem; }
/* THE HEADERS WRAP, and the row labels do not. It was the other way round, and
   "AVERAGE ERROR" on one line is 120px of column for a number three characters
   wide — which pushed the last column, the one the whole table exists to make a
   point about, off the right edge behind a scrollbar. */
.ei-ev-errtable .ei-ev-th { white-space: normal; line-height: 1.25; vertical-align: bottom; }
.ei-ev-errtable { min-width: 0; }
.ei-ev-errsum { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: .9rem; margin: 1rem 0 0; }
.ei-ev-errsum__i { display: flex; flex-direction: column; gap: .15rem; }
.ei-ev-errsum__v { font-size: 1.2rem; font-weight: 800; color: var(--ei-heading); font-variant-numeric: tabular-nums; line-height: 1.1; }
.ei-ev-errsum__l { font-size: .74rem; color: var(--ei-muted); line-height: 1.35; }

/* ------------------------------------------------------------------ */
/* Data credits — the simulator's block, copied as assets/atlas does.   */
/*                                                                      */
/* ⚠️ EVERY text rule here is scoped under .ei-sim-crs on purpose. These */
/* rows are <p>s inside .ei-seo, and `.ei-seo p` (style.css) sets        */
/* margin/font-size/line-height at specificity 0,1,1 — it beats a bare   */
/* single-class selector, so an unscoped .ei-sim-cr__meta silently       */
/* renders at body size with body margins. Keep the two-class form.      */
/* ------------------------------------------------------------------ */

.ei-sim-crs { margin: .9rem 0 1.4rem; }
.ei-sim-crs .ei-sim-cr { border-top: 1px solid var(--ei-border); position: relative; }
.ei-sim-crs .ei-sim-cr:last-of-type { border-bottom: 1px solid var(--ei-border); }
.ei-sim-crs .ei-sim-cr__head {
	display: flex; align-items: baseline; gap: .55rem;
	padding: .85rem 0; cursor: pointer; list-style: none;
}
.ei-sim-crs .ei-sim-cr__head::-webkit-details-marker { display: none; }
.ei-sim-crs .ei-sim-cr__head:focus-visible { outline: 2px solid var(--ei-navy); outline-offset: 3px; }
.ei-sim-crs .ei-sim-cr__label { font-weight: 800; font-size: 1.02rem; letter-spacing: -.01em; color: var(--ei-heading); }
.ei-sim-crs .ei-sim-cr__code {
	font-size: .68rem; font-weight: 800; letter-spacing: .1em;
	text-transform: uppercase; color: var(--ei-muted);
}
.ei-sim-crs .ei-sim-cr__count {
	margin-left: auto; font-size: .78rem; font-weight: 600;
	color: var(--ei-muted); font-variant-numeric: tabular-nums;
}
.ei-sim-crs .ei-sim-cr__head::after {
	content: "+"; margin-left: .7rem; color: var(--ei-muted);
	font-size: 1rem; font-weight: 700; line-height: 1;
}
.ei-sim-crs .ei-sim-cr[open] .ei-sim-cr__head::after { content: "\2212"; } /* − */
.ei-sim-crs .ei-sim-cr__body { padding: 0 0 .95rem; }
.ei-sim-crs .ei-sim-cr__cat { margin: 0 0 .95rem; }
.ei-sim-crs .ei-sim-cr__cat:last-child { margin-bottom: 0; }
.ei-sim-crs .ei-sim-cr__catname {
	margin: 0 0 .5rem;
	font-size: .72rem; font-weight: 800; letter-spacing: .1em; line-height: 1.4;
	text-transform: uppercase; color: var(--ei-navy);
}
.ei-sim-crs .ei-sim-cr__catn { color: var(--ei-muted); font-weight: 600; font-variant-numeric: tabular-nums; }
.ei-sim-crs .ei-sim-cr__src { margin: 0 0 .75rem; padding-left: .9rem; border-left: 2px solid var(--ei-border); }
.ei-sim-crs .ei-sim-cr__src:last-child { margin-bottom: 0; }
.ei-sim-crs .ei-sim-cr__name { margin: 0; font-size: .96rem; line-height: 1.4; font-weight: 600; }
.ei-sim-crs .ei-sim-cr__link {
	color: var(--ei-text); text-decoration: underline;
	text-underline-offset: 3px; text-decoration-thickness: 1px;
}
.ei-sim-crs .ei-sim-cr__link:hover,
.ei-sim-crs .ei-sim-cr__link:focus-visible { color: var(--ei-navy); }
/* A source with no single canonical page is NOT a link — it must not look
   clickable, but it still reads as the same kind of thing. */
.ei-sim-crs .ei-sim-cr__link--none { text-decoration: none; color: var(--ei-heading); }
.ei-sim-crs .ei-sim-cr__ext { margin-left: .3em; font-size: .8em; opacity: .7; font-variant-emoji: text; }
.ei-sim-crs .ei-sim-cr__meta {
	margin: .18rem 0 0;
	font-size: .76rem; line-height: 1.45; letter-spacing: .015em;
	color: var(--ei-muted); font-variant-numeric: tabular-nums;
}
.ei-sim-crs .ei-sim-cr__what { margin: .28rem 0 0; font-size: .88rem; line-height: 1.55; color: var(--ei-text); }

@media (max-width: 640px) {
	.ei-sim-crs .ei-sim-cr__head { flex-wrap: wrap; gap: .3rem .55rem; padding-right: 1.6rem; }
	.ei-sim-crs .ei-sim-cr__count { margin-left: 0; width: 100%; }
	.ei-sim-crs .ei-sim-cr__head::after { position: absolute; right: 0; top: .85rem; margin-left: 0; }
}

/* ==================================================================== */
/* MOTION                                                               */
/* ==================================================================== */

@media (prefers-reduced-motion: reduce) {
	.ei-ev-tr, .ei-ev-mode, .ei-ev-filter, .ei-ev-mapst { transition: none; }
}

/* ==================================================================== */
/* ONE [hidden] GUARD for every element this page hides in JS.          */
/*                                                                      */
/* `hidden` is only a UA rule (display:none at the lowest precedence),  */
/* so ANY class that sets display beats it and the element stays on     */
/* screen while reporting hidden === true. That has now bitten three    */
/* times here: both tooltips (display:grid) stayed visible, and the     */
/* hero's partial-count chip (.ei-fc__chip, display:inline-flex) paints */
/* as an empty pill when there is no partial state to report.          */
/*                                                                      */
/* ⚠️ Scoped to this page's own elements rather than a blanket          */
/* [hidden]{display:none!important}, which would override deliberate    */
/* display on markup the theme owns.                                    */
/* ==================================================================== */
.ei-page-early-vote [data-ev-chips] .ei-fc__chip[hidden],
.ei-ev-shell [hidden],
.ei-ev-tip[hidden],
.ei-ev-charttip[hidden] { display: none !important; }

/* --------------------------------------------------------------------------
   THE MEMBERS' 2024 ESTIMATE TAB
   --------------------------------------------------------------------------
   Every MODELLED 2024 figure on this page lives here now. It used to be spread
   across the three free tabs — a column in the state board, a card inside each
   state panel, a mode on the Overview's second map — and in the board's case it
   sat in a row where every other cell was something a state had COUNTED.

   ⚠️ THE TAB CARRIES NO TINT OF ITS OWN, and that is the same rule the thought
   experiment's own card states further up this file: a modelled figure is
   marked by its badge, its dotted frame and an uncertainty band wider than the
   shift it reports — never by colouring the container. A gold "premium" wash
   over the whole panel would say "this is the good stuff" about numbers whose
   entire caveat is that they are the uncertain stuff.
   -------------------------------------------------------------------------- */

/* The combined reading, above the map. ⚠️ Its coverage note is part of the card
   and not a tooltip — a figure over a fifth of the country reads very
   differently from one over three-quarters of it. */
.ei-ev-est24__natslot { display: block; margin-top: var(--ei-ev-card-gap); }
.ei-ev-est24__nat {
	margin: 0; padding: var(--ei-ev-card-pad-y) var(--ei-ev-card-pad-x);
}
.ei-ev-est24__natrow {
	display: grid; gap: .9rem 1.6rem;
	grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
	margin-top: var(--ei-ev-block-gap);
}
.ei-ev-est24__natfig { display: grid; gap: .15rem; }
.ei-ev-est24__natv {
	font-size: 1.75rem; font-weight: 800; line-height: 1.05;
	font-variant-numeric: tabular-nums; color: var(--ei-heading);
}
/* The extrapolated figure is the headline; the counted 2024 result beside it is
   context. Same colour language, different weight. */
.ei-ev-est24__natv.is-lead { font-size: 2.25rem; }
.ei-ev-est24__natv.is-dem { color: var(--ei-navy); }
.ei-ev-est24__natv.is-rep { color: var(--ei-red); }
.ei-ev-est24__natl { font-size: .78rem; line-height: 1.35; color: var(--ei-muted); }
.ei-ev-est24__natnote {
	margin: var(--ei-ev-block-gap) 0 0;
	font-size: .78rem; line-height: 1.5; color: var(--ei-muted);
}

/* ⚠️ NO RULE UNDER THE INFERENCE MAP'S HEADER. It runs the full width of the
   card while everything under it is inset, so it reads as a stray line rather
   than a separator — and the header it was dividing off is two lines and a pair
   of buttons. The other maps keep theirs. */
.ei-ev-infmap .ei-ev-maphead { border-bottom: 0; }

/* Map and reading side by side: the map asks "what about that state?" and the
   column beside it answers. Stacks on narrow screens, where two columns leave
   both halves too small to read. */
.ei-ev-est24__geo {
	display: grid; gap: var(--ei-ev-card-gap);
	grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
	align-items: start;
	margin-top: var(--ei-ev-card-gap);
}
@media (max-width: 900px) {
	.ei-ev-est24__geo { grid-template-columns: minmax(0, 1fr); }
}

.ei-ev-est24__map,
.ei-ev-est24__detailslot,
.ei-ev-est24__boardslot { display: block; min-width: 0; }

.ei-ev-est24__boardslot { margin-top: var(--ei-ev-card-gap); }

/* The selected state's reading. The card inside brings its own dotted frame and
   badge, so this wrapper only supplies the header row above it. */
.ei-ev-est24__detailhead {
	display: flex; align-items: baseline; justify-content: space-between;
	gap: .6rem; margin-bottom: var(--ei-ev-block-gap);
}
.ei-ev-est24__detailh {
	margin: 0; font-size: 1rem; font-weight: 800; color: var(--ei-heading);
}
.ei-ev-est24__close {
	appearance: none; background: none; border: 0; padding: 0;
	font: inherit; font-size: .78rem; color: var(--ei-muted);
	cursor: pointer; text-decoration: underline; text-underline-offset: 2px;
}
.ei-ev-est24__close:hover { color: var(--ei-heading); }

/* The resting state. It names the gesture rather than leaving an empty column
   that reads as a component which failed to load. */
.ei-ev-est24__hint {
	margin: 0; padding: var(--ei-ev-card-pad-y) var(--ei-ev-card-pad-x);
	border: 1px dashed var(--ei-line, rgba(128,128,128,.35));
	border-radius: .5rem;
	font-size: .82rem; line-height: 1.55; color: var(--ei-muted);
}

/* A board row opens the same panel the map does. */
.ei-ev-est24__table .ei-ev-tr.is-clickable { cursor: pointer; }
.ei-ev-est24__table .ei-ev-tr.is-clickable:hover,
.ei-ev-est24__table .ei-ev-tr.is-clickable:focus-visible {
	background: color-mix(in srgb, currentColor 6%, transparent);
	outline: none;
}

.ei-ev-est24__intro,
.ei-ev-est24__board {
	margin: 0; padding: var(--ei-ev-card-pad-y) var(--ei-ev-card-pad-x);
}

/* The standing caveat, at reading size. On the old board this was a column
   hint most readers never opened. */
.ei-ev-est24__warn {
	margin: var(--ei-ev-block-gap) 0 0;
	padding: .6rem .75rem;
	border-left: 3px solid var(--ei-gold, #e6b94e);
	background: color-mix(in srgb, var(--ei-gold, #e6b94e) 8%, transparent);
	border-radius: 0 .35rem .35rem 0;
	font-size: .82rem; line-height: 1.5; color: var(--ei-text);
}

/* The normal state for most of the season — written out, never a blank tab. */
.ei-ev-est24__empty {
	margin: var(--ei-ev-block-gap) 0 0;
	font-size: .85rem; line-height: 1.6; color: var(--ei-muted);
}

.ei-ev-est24__table { width: 100%; }
.ei-ev-est24__table .ei-ev-td,
.ei-ev-est24__table .ei-ev-th { white-space: nowrap; }

/* One card per reporting state, stacked. They carry their own dotted frames,
   so the only thing needed here is the rhythm between them. */
.ei-ev-est24__cards { display: grid; gap: var(--ei-ev-card-gap); }

/* The wall a non-member meets. The panel itself is .ei-brief-gate, styled with
   every other wall on the site in style.css; this only gives it the same
   breathing room the real tab's cards have. */
.ei-ev-gate { display: block; margin: 0; }
.ei-ev-gate--estimate { margin-top: var(--ei-ev-card-gap); }
