/* The shared component library.
 *
 * Everything here is a piece the forecast is drawn from -- the chamber and
 * its party bands, the bloc composition bars, the coalition builder, the
 * caption-rail plate, the figure treatment -- and none of it knows which
 * site it is on. That is the point: the public site renders the same
 * chamber, from the same `charts.py`, under the same tokens.
 *
 * Requires tokens.css.
 */

/* ---- swatch ----------------------------------------------------------- */

.swatch {
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  margin-inline-end: 0.5rem;
  vertical-align: baseline;
}

/* ---- a list's mark ----------------------------------------------------- */

/* One slot at the head of a list's row, the same size whether or not we hold
 * the list's emblem.
 *
 * Most lists have no emblem and that is the design's ordinary case, not its
 * edge: the corpus runs back to 2009 and carries parties that folded a decade
 * ago. So the slot is sized by the box and never by its contents -- a table
 * where no list has an emblem is the table that was here before, indented,
 * and one where every list does has the same rhythm. Nothing reflows on the
 * difference.
 *
 * It replaces the bloc swatch rather than joining it. Two marks before one
 * name is the clutter this was meant to remove, and the row keeps its colour:
 * the distribution strip beside it is drawn in the bloc's own hue.
 */
/* The box is landscape, and that is the one measurement here worth arguing
   about. Israeli party emblems are overwhelmingly *wordmarks* -- the party's
   name set in its own face -- and their aspect ratios run from about 1:1 to
   nearly 9:1. Fitted into a square, a 3.5:1 wordmark is six pixels tall and
   reads as a coloured smudge; at 2.5rem by 1.5rem the same mark is legible,
   and the square devices that do exist -- Shas's tablets, Otzma Yehudit's
   star -- still fill the height. */
.list-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 2.5rem;
  block-size: 1.5rem;
  flex: none;
  margin-inline-end: 0.5rem;
  vertical-align: -0.45rem;
}

/* The card. `contain` is what keeps the mark unaltered: emblems arrive at
   every aspect ratio a design studio can invent -- a 3:1 wordmark and a square
   device sit in the same column -- and anything but `contain` would crop or
   stretch one of them. */
.list-mark img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  background: var(--emblem-card);
  border: 1px solid var(--emblem-edge);
  border-radius: 3px;
  padding: 2px;
}

/* The same mark on a line of type, at two-fifths of the area it has in the
 * table. Two places set it this way: the caption of a small multiple, and a
 * row of the coalition builder.
 *
 * A cell of the small multiples is 13rem wide and its caption is set at
 * 0.8rem, so the table's box would take a fifth of the cell's width and
 * outweigh the sparkline it labels. A builder row is one line of 0.84rem with
 * a checkbox and a seat count on it, and the table's box would be taller than
 * the line. This one is sized to the line instead: a little taller than the
 * type, which is enough to tell one mark from the others and not enough to
 * read a wordmark off. That is what a name on a line needs and all it needs --
 * the name is set right beside it, and the mark is here to be recognised
 * rather than read.
 *
 * Every measurement is in `em` rather than `rem` because the type it sits in
 * is: the lockup holds together when a reader sizes the text up. And it is
 * shorter than the line it sits on in both places, so adding it moved no row:
 * the caption's line is 1.25em and the builder's is the body's.
 *
 * In neither place is the mark an inline box. It is a grid item in the caption
 * and a flex item in the builder, because an atomic inline offers the line
 * breaker somewhere to break on either side of it whether or not whitespace is
 * there, and at a narrow column it took it -- the mark on the caption's first
 * line with the name underneath, which under the `-webkit-line-clamp: 2` below
 * costs a two-line name one of the two lines it is allowed. A word joiner does
 * not stop that break in Chromium and a float reproduces it. A grid or flex
 * item is not offered to the line breaker at all. */
.trend-cell .list-mark,
.coal-picker .list-mark {
  inline-size: 2em;
  block-size: 1.2em;
}

/* The gap rides on the mark rather than on the row, in both places, and for
   the same reason: it has to be absent when the mark is. `_mark.html` draws
   nothing for a list in the small multiples we hold no emblem for, and a `gap`
   between two tracks is there whether or not either has anything in it. The
   builder's rows already carry a `gap` for the checkbox, so there the margin
   is taken back to nought instead. */
.trend-cell .list-mark { margin-inline-end: 0.35em; }
.coal-picker .list-mark { margin-inline-end: 0; }

/* The card's edge goes at this size. Counted top and bottom, a 1px rule is an
   eighth of a box this small, and what it draws is the box rather than the
   mark. The card itself stays: the mark is unaltered, so it keeps the ground
   it was drawn for. */
.trend-cell .list-mark img,
.coal-picker .list-mark img { border: 0; padding: 1px; }

/* No emblem: the bloc swatch, in the middle of the same box. */
.list-mark.bare::before {
  content: "";
  inline-size: 9px;
  block-size: 9px;
  border-radius: 2px;
  background: var(--mark-tint, var(--unaffiliated));
}

/* ---- the caption rail ------------------------------------------------ */

/* A panel is an instrument with its caveat beside it. On a narrow screen the
   rail stacks above, which is the same reading order. */
.plate { display: grid; grid-template-columns: var(--rail) minmax(0, 1fr); gap: 2.5rem; align-items: start; }
.plate > .rail { position: sticky; top: 1.5rem; }
.plate .rail p {
  font-family: var(--prose);
  font-variation-settings: "opsz" 11;
  font-size: 0.94rem;
  line-height: 1.5;
  color: var(--muted);
  margin: 0 0 0.9rem;
  max-width: 42ch;
}
.plate .rail p:last-child { margin-bottom: 0; }
.plate > table { align-self: start; }

@media (max-width: 900px) {
  .plate { grid-template-columns: minmax(0, 1fr); gap: 1.25rem; }
  .plate > .rail { position: static; }
}

/* ---- figures --------------------------------------------------------- */

/* A number worth reading across the room, over a hairline, with its label
   below in the same mono the tables use. */
.figures { display: flex; flex-wrap: wrap; gap: 0 2.75rem; }
.figures > div { display: flex; flex-direction: column-reverse; padding-top: 0.55rem; border-top: 1px solid var(--rule); min-width: 5.5rem; }
.figures b {
  font-family: var(--display);
  font-variation-settings: "wdth" 115;
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.figures span {
  font-family: var(--mono-label);
  font-size: 0.68rem;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* ---- the chamber ---------------------------------------------------- */

/* Capped rather than filling the panel: on a wide monitor an unconstrained
   arc pushes everything else below the fold, and the seat dots gain nothing
   from being enormous. */
.chamber { display: block; margin: 0 auto; width: 100%; max-width: 900px; height: auto; }

.chamber circle { transition: r 120ms ease; }
.chamber circle:hover { r: 7; }

/* The 61 rule. One dash, one weight, one colour -- here, in the composition
   bars and in the coalition track. See the file header. */
.majority-line {
  stroke: var(--majority);
  stroke-width: var(--majority-width);
  stroke-dasharray: var(--majority-dash);
  opacity: 0.5;
}
.majority-label {
  font-family: var(--mono-label);
  font-size: 11.5px;
  fill: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

/* --- party bands on the chamber ------------------------------------------ */

/* A hairline of surface between neighbouring bands, so two parties of one
   bloc -- adjacent steps of a single hue -- still read as two. */
.band path { stroke: var(--surface); stroke-width: 1.5; transition: opacity 120ms ease; }
/* These name the wedges of the chart and were the palest thing on the page at
   the smallest size on it, which is the wrong way round. The name takes most
   of the ink contrast; the count takes all of it. */
/* `--mono` and not `--mono-label`, which is the exception to the rule that
   token describes and the only kind of exception there is. Nothing here lines
   up in a column, so by that test this label wants Assistant first -- but
   `typography.py` measures these strings to size the chamber's box and to
   decide when a name is shortened, and it charges Plex Mono's 0.600em for
   every character outside the Hebrew block, U+0020 among them. Narrowing the
   space on the page without re-measuring the advances would leave the model
   describing a label the page no longer draws. Re-measuring is the ritual in
   that module's docstring and it moves the geometry, so it is its own change;
   until then this label and `.threshold-axis` keep the face the model
   assumes. */
.band-label {
  font-family: var(--mono);
  font-size: 12.5px;
  fill: color-mix(in oklab, var(--ink) 84%, var(--surface));
  pointer-events: none;
  transition: fill 120ms ease;
}
.band-count { fill: var(--ink); font-weight: 600; }

/* --- linking the chamber to the bars ------------------------------------- */

/* Hovering a party anywhere dims every other party everywhere. The chamber
   answers "how many"; this is what answers "whose". */
.linked .seat, .linked .band path, .linked .comp-seg { opacity: 0.22; }
.linked .band-label { fill: var(--rule); }
/* `.on` lands on the element carrying `data-list`, which for a band is the
   group rather than the path it wraps. Targeting `.band path.on` matches
   nothing, and the band alone stays dark while its seats light up. */
.linked .seat.on, .linked .band.on path, .linked .comp-seg.on { opacity: 1; }
.linked .band-label.on { fill: var(--ink); }

/* --- bloc composition bars ----------------------------------------------- */

.composition { display: grid; gap: 0.85rem; }
.comp-row {
  display: grid;
  grid-template-columns: minmax(7rem, 12rem) 1fr 2.5rem;
  align-items: center;
  gap: 0.9rem;
}
.comp-name { font-size: 0.85rem; display: flex; align-items: center; gap: 0.4rem; }
.comp-total { font-family: var(--mono); font-weight: 600; text-align: end; }

.comp-track { position: relative; height: 30px; background: var(--surface-sunken); border-radius: 4px; }
.comp-seg {
  position: absolute;
  top: 0;
  bottom: 0;
  /* The 2px surface gap that keeps adjacent steps of one hue separable. */
  box-shadow: inset -2px 0 0 var(--surface);
  /* Mirrored below for RTL, where the gap belongs on the other edge. */
  transition: opacity 120ms ease;
  overflow: hidden;
}
.comp-seg:first-child { border-start-start-radius: 4px; border-end-start-radius: 4px; }
.comp-seg:last-child { border-start-end-radius: 4px; border-end-end-radius: 4px; box-shadow: none; }
.comp-seg span {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  padding-inline-start: 0.45rem;
  /* The trailing inset is what the count stands in. Without it the count sits
     flush against the segment's edge and the 2px separator paints over the
     last of it, which is the same wrong number by another route. */
  padding-inline-end: 0.45rem;
  font-family: var(--mono);
  font-size: 0.7rem;
  /* The segment is a step away from the page, so the page colour is the
     legible ink on it in either theme. */
  color: var(--surface);
  white-space: nowrap;
}
.comp-seg span.count-only { justify-content: center; padding-inline: 0; }
/* The span is a flex container, so a text node between its children -- and a
   generated `content: " "` -- collapses to nothing and the name runs straight
   into the count. The gap has to be a margin.

   The name used to arrive already cut, at sixteen characters in the template,
   which is the measure the chamber stopped using: Jinja's `truncate` carries
   five characters of leeway, so it let long names through whole and cut others
   mid-word, and neither cut knew how wide the segment had come out. It is now
   set whole and clipped here. This is the one figure on the site that can do
   that, because it is HTML: the browser knows the real advances of the real
   face at the real size, which no table of measurements offline can. */
.seg-name {
  font-style: normal;
  margin-inline-end: 0.45em;
  /* A flex item will not shrink below its own text without this. */
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* The count is the half that must survive: a clipped name is shorter than the
   name, a clipped number is a different number. */
.seg-count { font-style: normal; flex: none; }

/* The seat threshold that decides whether a segment gets a name is a proxy for
   how wide that segment will be, and the proxy breaks on a phone: a 23-seat
   segment is 19% of the bar, which is about 134px on a desktop and about 46px
   here. `overflow: hidden` then cut "Likud 23" down to "Likud 2" -- a clipped
   number is not a cramped label, it is a wrong one. Below this width the name
   goes and the count stays, centred; identity is still carried by the colour,
   the legend, and the table underneath. */
@media (max-width: 860px) {
  .comp-seg .seg-name { display: none; }
  .comp-seg span { justify-content: center; padding-inline: 0; }
}

/* The same 61 in every bar. The distance from a bar's end to this line is the
   bloc's distance from a majority, which is the whole question. */
.comp-majority {
  position: absolute;
  inset-inline-start: var(--majority-at);
  top: -5px;
  bottom: -5px;
  width: 0;
  border-inline-start: var(--majority-width) dashed var(--majority);
  opacity: 0.5;
  z-index: 2;
}

/* --- the coalition builder ----------------------------------------------- */

.coal-presets { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1rem; }
.coal-preset {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font: inherit;
  font-size: 0.8rem;
  color: var(--ink);
  background: var(--surface-sunken);
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: 0.3rem 0.75rem;
  cursor: pointer;
}
.coal-preset:hover { border-color: var(--ink); }

.coal-picker {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
  margin-bottom: 1.25rem;
}
/* `min-width: 0` is the whole fix for a grid column that refuses to shrink.
   Grid items default to `min-width: auto`, which is the width of their widest
   unbreakable content -- so a list whose legal name runs to eight words pushed
   its fieldset past its own border and over the neighbouring column, taking
   its seat count with it. */
.coal-picker fieldset {
  min-width: 0;
  border: 1px solid var(--rule);
  border-radius: 6px;
  padding: 0.6rem 0.8rem 0.8rem;
  margin: 0;
}
.coal-picker legend { display: flex; align-items: center; gap: 0.4rem; font-size: 0.78rem; color: var(--muted); padding: 0 0.35rem; }
.coal-picker label {
  display: flex;
  align-items: center;
  min-width: 0;
  gap: 0.45rem;
  padding: 0.22rem 0;
  font-size: 0.84rem;
  cursor: pointer;
}
/* The row's own colour, whose slot the mark took and whose job it cannot do.
 * Reading a row against its segment of the composition bar means finding the
 * same list twice, and the bar carries no marks: it names a segment only from
 * thirteen seats up and prints a bare count below that, so for most lists the
 * shade is the whole of what a segment is identified by.
 *
 * A hairline ahead of the mark rather than the swatch back. The swatch was a
 * box that held the name's column open and the mark holds that now; this is
 * three pixels and opens nothing, which is enough to match a colour against
 * and too little to read as a second mark before the name. It is not on the
 * mark either: an emblem ships unaltered and keeps the ground it was drawn
 * for, so the card cannot be tinted.
 *
 * Shorter than the row on purpose. The bar keeps a 2px surface gap between
 * adjacent steps of one hue because two of them butted together read as one,
 * and a rule as tall as its row would butt against the rows above and below
 * in exactly that way. */
.coal-picker .row-tint {
  flex: none;
  inline-size: 3px;
  block-size: 1.2em;
  border-radius: 2px;
}
/* A list's full legal name can run to eight words. It is on the element as a
   title and in the table below; here it only has to be identifiable. */
.coal-picker label span { flex: 1 1 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.coal-picker label b { font-family: var(--mono); font-size: 0.8rem; flex: none; }

.coal-track {
  position: relative;
  height: 34px;
  background: var(--surface-sunken);
  border-radius: 4px;
  overflow: visible;
  margin-bottom: 1rem;
}
.coal-fill {
  height: 100%;
  border-radius: 4px;
  background: var(--unaffiliated);
  transition: width 160ms ease, background 160ms ease;
}
/* The one moment the builder has an opinion: this selection governs. */
.coal-fill.has-majority { background: var(--bloc-a); }
.coal-majority {
  position: absolute;
  inset-inline-start: var(--majority-at);
  top: -6px;
  bottom: -6px;
  border-inline-start: var(--majority-width) dashed var(--majority);
  opacity: 0.5;
}

/* `.coal-stats` also carries `.figures`, which supplies the treatment; this
   only holds the one figure that is a phrase rather than a number. */
.coal-stats [data-field="verdict"] { font-size: 1.15rem; font-variation-settings: "wdth" 100; }

@media (prefers-reduced-motion: reduce) {
  .coal-fill { transition: none; }
}

/* --- expandable bloc rows ------------------------------------------------ */

.bloc-members summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: 0.4rem; }
.bloc-members summary::-webkit-details-marker { display: none; }
.bloc-members summary::after {
  content: "›";
  color: var(--muted);
  transition: transform 120ms ease;
  display: inline-block;
}
.bloc-members[open] summary::after { transform: rotate(90deg); }
.bloc-members ul { margin: 0.5rem 0 0.25rem; padding: 0 0 0 0.3rem; list-style: none; }
.bloc-members li {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.82rem;
  color: var(--muted);
  padding: 0.15rem 0;
}
.bloc-members li b { font-family: var(--mono); color: var(--ink); margin-inline-start: auto; padding-inline-start: 1rem; }

/* The names around the arc are not set at a size of their own: the figure
   scales, so they scale with it. At 1440 they land at 13.4px and at 390 at
   5.8px, which is decoration in the shape of information. They go the same way
   the segment names above go, and at the width the rest of this figure already
   reflows at -- the arc keeps every fallback: the readout names a list on tap,
   the legend carries the blocs, and the table below carries all of it.

   640 rather than the 860 the segment names use, because that number is the
   bars' own arithmetic and does not transfer. What is left to read here is not
   monotonic in the viewport: the two-column layout above 1240 hands the
   chamber a narrower column than a 700px phone does, and ships 10.2px labels
   there. 640 is where the labels first fall below that -- 9.8px, against
   13.1px at 860, which is a size worth keeping.

   `aspect-ratio` is the other half. See `charts.chamber_arc_ratio`: the box
   still holds the room the names would have needed, and this is what crops it
   off, which is worth about half as much figure again. */
@media (max-width: 640px) {
  .comp-row { grid-template-columns: 1fr 2.5rem; }
  .comp-name { grid-column: 1 / -1; }
  .band-label { display: none; }
  .chamber { aspect-ratio: var(--chamber-arc-ratio); }
}

@media (prefers-reduced-motion: reduce) {
  .band path, .band-label, .comp-seg, .bloc-members summary::after { transition: none; }
}

.legend { display: flex; gap: 1.5rem; justify-content: center; margin-top: 0.5rem; flex-wrap: wrap; }
.legend span { font-family: var(--mono-label); font-size: 0.78rem; color: var(--muted); }

/* ---- a figure the law does not allow ---------------------------------- */

/* A seat count between nothing and the threshold's minimum is withheld rather
   than printed, so the cell has to read as a deliberate absence and not as a
   missing value. The dagger beside the list's name carries the explanation;
   the rule under the dash is what stops the cell reading as an empty one. */
.withheld {
  color: var(--muted);
  border-bottom: 1px dotted currentColor;
  cursor: help;
}

.marker {
  font-family: var(--mono);
  font-size: 0.7em;
  vertical-align: super;
  margin-inline-start: 0.15em;
  color: var(--muted);
  text-decoration: none;
}

.marker:hover, .marker:focus-visible { color: var(--ink); }

/* ---- discrete distribution strips ----------------------------------- */

/* Seats are integers, so the distribution is drawn as discrete bars rather
   than a smoothed curve. The shape is the honest one. */
.strip { display: flex; align-items: flex-end; gap: 1px; height: 34px; }

.strip i {
  flex: 1;
  min-width: 2px;
  background: var(--unaffiliated);
  opacity: 0.45;
  border-radius: 1px 1px 0 0;
}

.strip i.marked { opacity: 1; }

/* Where the result actually landed. Drawn inside the predictive distribution
   rather than beside it, so the calibration reads at a glance: a miss in the
   body of the distribution is the model working, one out in the tail is not. */
.strip i.actual {
  background: var(--ink) !important;
  opacity: 1;
  outline: 1px solid var(--ground);
}



/* ---- the polling figures ---------------------------------------------- */

/* Three marks, three quantities, and none of them is decoration:
 *
 *   band   how far the polls the model is reading disagree with one another
 *   dot    one poll, at the date it was fielded
 *   spine  the aggregator's own average, as thick as the evidence behind it
 *
 * The spine is a filled shape rather than a stroked line because its width
 * carries a variable; a stroke has one width, and one width would say a
 * single poll and seventy settle a question equally. It takes a ring of the
 * surface colour so that two spines crossing stay two spines -- which they do
 * here, repeatedly, because the two large blocs keep changing places.
 */

.trend-plot {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
  /* Time runs left to right in both languages. It is a scale, not a sentence:
     the same reason the chamber is not mirrored. */
  direction: ltr;
}

.trend-grid { stroke: var(--rule); stroke-width: 1; }
.trend-eday { stroke: var(--ink); stroke-width: 1; opacity: 0.4; }

/* The day the Knesset dissolved. Dashed rather than solid because it divides
   the axis into two kinds of evidence rather than ending it, which is what
   polling day does. */
.trend-dissolved {
  stroke: var(--ink);
  stroke-width: 1;
  stroke-dasharray: 3 4;
  opacity: 0.7;
}
/* Filled *and* stroked, at a fill weak enough that two bands over one
   another stay two. The edge carries the identity: a fill this pale is a
   region, and the line around it is which bloc's region. */
.trend-band {
  fill-opacity: 0.12;
  stroke-width: 1;
  stroke-opacity: 0.55;
}
/* Six hundred marks, four pixels across, in three hues that a colour-blind
   reader has to tell apart. At 0.55 the fill composited against the surface to
   a pair 11.4 apart in OKLab -- under the 15 the palette check calls a floor
   for full-colour vision, let alone reduced -- and the two clusters inside each
   bloc's band, which is the one thing the marks exist to show, went soft. Kept
   opaque enough to hold its hue, and given a ring of the surface so that a
   hundred overlapping dots stay countable. */
.trend-dot {
  fill-opacity: 0.85;
  stroke: var(--surface);
  stroke-width: 0.7;
  stroke-opacity: 0.85;
}

.trend-spine {
  stroke: var(--surface);
  stroke-width: 1.2;
  paint-order: stroke fill;
}

.trend-lead { fill: none; stroke-width: 1; opacity: 0.55; }

/* 12.5px in a 1000-unit viewBox. The plate's content column runs from about
   780px to 1076px, so this lands between 10px and 13px on the page -- the
   band the rest of the site's small type sits in. */
.trend-axis {
  font-family: var(--mono-label);
  font-size: 12.5px;
  fill: var(--muted);
}

.trend-61 { fill: var(--ink); }

.trend-name {
  font-family: var(--display);
  font-variation-settings: "wdth" 104;
  font-size: 12.5px;
  font-weight: 600;
}

.trend-range {
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* The threshold floor, on the per-list cells only. It is the line that decides
   whether a list exists at all, so it is drawn in the alert hue rather than in
   the grid's. No bloc is near it, so the bloc figure does not carry it. */
.trend-floor {
  stroke: var(--alert);
  stroke-width: 1;
  stroke-dasharray: 3 3;
  opacity: 0.6;
}

/* Two layouts of one campaign, not one scaled twice. The wide one carries six
   hundred poll marks and a tick a quarter; below about 780px of column those
   become three pixels apart and six pixels tall, so the narrow one leaves both
   out and `.trend-drops` says so.
 *
 * The switch is at 1180px of viewport rather than at a phone's width because
 * the narrowest the content column ever gets is not on a phone: it is at
 * 901px, one pixel above the width at which the rail stops sitting beside the
 * figure and stacks above it. There the column is about 510px, narrower than
 * the same figure gets on a 700px tablet. */
.trend-narrow,
.trend-drops { display: none; }

/* Capped so that the narrow figure, which is 360 units wide, is never blown up
   past about a quarter again -- it is a small chart, not a large one waiting
   for room. */
.trend-narrow { max-width: 460px; margin-inline: auto; }

@media (max-width: 1180px) {
  .trend-wide { display: none; }
  .trend-narrow { display: block; }
  .trend-drops { display: block; }
}

.trend-drops {
  font-size: 0.82rem;
  color: var(--muted);
  margin: 0.75rem 0 0;
}

/* The key to the encodings. Four rows, one mark each, drawn by `charts.py`
   from the constants the figure is drawn from -- so the tapering swatch is as
   thick at each end as the real line, and stays so if the real line changes.
   Set in ink rather than in a bloc's hue: these entries name what a mark
   means, not which bloc it belongs to, and the block below names the blocs. */
.trend-legend {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: 0.65rem 2rem;
  margin: 0 0 0.4rem;
  padding: 0;
  list-style: none;
}

.trend-legend li {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-size: 0.82rem;
  color: var(--muted);
}

.trend-swatch {
  flex: none;
  width: 48px;
  height: 20px;
  overflow: visible;
  fill: var(--ink);
  stroke: var(--ink);
}

/* The three marks have to be told apart at 48 by 20 user units, in ink rather
   than in a bloc's hue, so each keeps the quality that distinguishes it in the
   figure: the line is solid, the band is a pale wash inside a thin edge, and
   the dots are dots. */
.trend-swatch .trend-spine { stroke: none; fill-opacity: 0.85; }
.trend-swatch .trend-band { fill-opacity: 0.28; stroke-opacity: 0.5; }
.trend-swatch .trend-dot { fill-opacity: 0.85; stroke: var(--surface); }

/* The legend and the finding in one block. Each bloc gets the range of today's
   polls and the range its average has held, which are the two quantities the
   figure asks the reader to compare. Deliberately not a seat count: the page
   prints one of those per bloc already, from the run's canonical allocation,
   and a second one a seat away would be two totals for one set of parties. */
.trend-key {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.25rem 2rem;
  margin: 1.5rem 0 0;
  padding-top: 1.1rem;
  border-top: 1px solid var(--rule);
}

.trend-key > div { min-width: 0; }

.trend-key dt {
  display: flex;
  align-items: center;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.92rem;
  margin-bottom: 0.35rem;
}

.trend-key dd {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0 0 0.15rem;
}

.trend-key dd span { font-size: 0.78rem; color: var(--muted); }

.trend-key dd b {
  font-family: var(--mono);
  font-size: 0.95rem;
  font-variant-numeric: tabular-nums;
}

.trend-table-head {
  font-family: var(--display);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin: 2rem 0 0.6rem;
}

/* A `<caption>`, not a paragraph above the table: it is the table's own
   accessible name, and this table is the figure's equivalent for a reader who
   cannot use the figure. */
.trend-table-note {
  caption-side: top;
  text-align: start;
  font-size: 0.82rem;
  color: var(--muted);
  margin: 0 0 0.9rem;
  max-width: 52ch;
}

/* "poll average", under the bloc's name in the column head. The number in the
   cell has a decimal and no seat count on this site does, but a decimal is a
   hint and a word is not, and on a phone the head is hidden and the cell's own
   label carries the word instead. */
.trend-th-note {
  display: block;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  opacity: 0.85;
}

.trend-table { width: 100%; border-collapse: collapse; font-size: 0.84rem; }

.trend-table th,
.trend-table td { padding: 0.45rem 0.75rem; border-bottom: 1px solid var(--rule); vertical-align: baseline; }

.trend-table th {
  font-family: var(--display);
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  text-align: start;
  border-bottom-color: var(--ink);
  white-space: nowrap;
}

.trend-table th.num { text-align: end; }
.trend-table .trend-when { white-space: nowrap; }

/* Two figures in one cell: the average, and under it the polls it came from.
   Stacked rather than given a column each, because the table then fits a
   phone without either being dropped. */
.trend-table td.num b { display: block; font-weight: 600; }
.trend-table td.num span { display: block; font-size: 0.76rem; color: var(--muted); }

/* Below this the row stops being a row. Five columns and a date do not fit in
   390px, and `.scroll` gives up its sideways scroll at the same width -- the
   site decided once that a page which scrolls down must not also scroll
   across, and this table is not the place to reopen it. */
@media (max-width: 640px) {
  .trend-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  /* Six tracks so the row breaks where the meaning does: the date across the
     top, the two counts of what the model was reading, then one cell per bloc.
     Three tracks put the first bloc on the counts' line and left a hole under
     the last. */
  .trend-table tr {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 0.5rem 0.9rem;
    padding: 0.8rem 0;
    border-bottom: 1px solid var(--rule);
  }
  .trend-table td { border: 0; padding: 0; text-align: start; grid-column: span 2; }
  .trend-table td:nth-child(2),
  .trend-table td:nth-child(3) { grid-column: span 3; }
  .trend-table .trend-when { grid-column: 1 / -1; font-family: var(--display); font-weight: 600; }
  .trend-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-family: var(--display);
    font-size: 0.6rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
  }
}

/* One cell per list, every one of them on the same seat axis. A grid rather
   than a column because the comparison is between lists, and a reader
   comparing sixteen things one screen apart is not comparing them. */
.trend-cells {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 1.4rem 1.6rem;
}

.trend-cell { margin: 0; min-width: 0; }

.trend-cell figcaption {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  padding-bottom: 3px;
  border-bottom: 1px solid var(--rule);
  /* Two lines' worth, always. A list whose name wraps would otherwise push its
     chart down and break the row the grid exists to align. */
  min-height: 2.6em;
}

/* The name, with the list's mark in a track of its own.
 *
 * Two tracks, so the mark and the name are two boxes rather than one line with
 * the mark set into it. Neither can be drawn over the other, because tracks do
 * not overlap; and neither can be broken away onto a line of its own, because
 * a grid item is never offered to the line breaker. Both of those are the box
 * model rather than a browser's reading of it, which is the point: what this
 * replaced took the mark out of flow and held its room with `text-indent`,
 * inside a `-webkit-box` carrying a line clamp, in a right-to-left column.
 * Chromium honoured the indent at every width. Safari on iPadOS did not, and
 * drew every Hebrew name's first word underneath its mark.
 *
 * `auto` collapses to nothing when there is no mark to put in it -- in this
 * one place `_mark.html` draws nothing rather than a swatch -- so a caption
 * for a list we hold no emblem for starts exactly where it always did. The gap
 * is the mark's own margin and not this grid's, for the same reason.
 *
 * `minmax(0, 1fr)` rather than `1fr`: a track's automatic minimum is its
 * content's, so one long unbreakable name would push the caption past the cell
 * and the cell past its column.
 *
 * What changed for the reader is the second line. A wrapped name used to start
 * at the caption's edge, under the mark; it now starts under the first line.
 * That is the better of the two -- the name is one block with one start edge,
 * and the mark stands beside the whole of it rather than over part of it --
 * and it costs the second line the mark's width, which at 13rem is about three
 * Hebrew characters of a name already clamped at two lines. */
.trend-cell figcaption .list-name {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  font-size: 0.8rem;
  line-height: 1.25;
  min-width: 0;
}

/* The mark to the top of the row rather than to the name's baseline: the box
   is 1.2em in a line 1.25em tall, so aligning the tops centres it to within a
   fortieth of an em, and a baseline would sit the card's bottom edge on the
   type's and push the mark above the line. Leaving the name as the only
   baseline-aligned item is also what the caption is aligned by: the range
   beside it is set to the name's first baseline, not to the mark's. */
.trend-cell figcaption .list-name > .list-mark { align-self: start; }

/* Clipped to two lines rather than truncated to a character count. Twenty
   characters cut `Unity (fmr. Erdan-E…` exactly where the disambiguator was,
   and was the right count for one of the two languages.

   On the name's own element rather than on the box that holds the mark: a
   `-webkit-box` with a clamp counts every line in it, and the mark is not a
   line of the name. */
.trend-cell figcaption .list-name > span {
  min-width: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
}

.trend-cell figcaption b {
  font-family: var(--mono);
  font-size: 0.9rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The hover link the chamber and the bars already share. A list picked out
   anywhere on the page is picked out here too, and the rest recede. */
.linked .trend-cell { opacity: 0.35; }
.linked .trend-cell.on { opacity: 1; }
.trend-cell { transition: opacity 120ms ease; }

@media (prefers-reduced-motion: reduce) {
  .trend-cell { transition: none; }
}


/* ---- right-to-left ----------------------------------------------------- */

/* Hebrew mirrors the page. What follows is the short list of places where a
   logical property could not do the job on its own.
 *
 * The chamber is deliberately absent from it. It is a seating plan rather than
 * a sentence -- the Knesset's benches do not swap ends when a reader switches
 * language, and every Israeli broadcaster draws the arc the same way -- so its
 * geometry stays put and only its labels take the new direction. */

/* `text-anchor` is resolved against the element's inline base direction, so a
   text element inheriting `dir="rtl"` swaps what start and end mean. The band
   anchors are geometric -- a label to the left of the arc has to extend
   leftward -- so the element stays LTR and the label itself is isolated, which
   orders the Hebrew correctly without moving the anchor. Inheriting the page
   direction here put every label on top of the chamber. */
.band-label { direction: ltr; }

/* A figure like "43-60" or "5.0%" is a single Latin run inside a Hebrew page.
   Without an isolate the bidi algorithm reorders it and the interval arrives
   as "60-43", which is a different and wrong statement. */
[dir="rtl"] .figures b,
[dir="rtl"] .coal-stats b,
[dir="rtl"] .comp-total,
[dir="rtl"] .band-count { unicode-bidi: isolate; direction: ltr; }
.band-label tspan { unicode-bidi: isolate; }

/* The 61 annotation is one string, `61 · majority`, and two figures on this
   page draw it. The chamber's sits in an SVG that takes the page's direction,
   the trend figure's in one pinned `direction: ltr`, so in Hebrew the same
   four characters came out in opposite orders a screen apart. The trend
   figure's plot stays pinned -- time is a scale, not a sentence -- and this
   one label opts back into the reader's direction, which is what the chamber
   already gives it. */
/* `text-anchor` as well as `direction`, because the two are resolved together:
   in a right-to-left run "end" is the left-hand side, which is what keeps a
   label positioned at the left edge of the plot growing rightwards instead of
   off the viewBox. Without it the annotation reversed and then clipped. */
[dir="rtl"] .trend-61 { direction: rtl; text-anchor: end; }

[dir="rtl"] .comp-seg { box-shadow: inset 2px 0 0 var(--surface); }
[dir="rtl"] .comp-seg span { padding-inline-start: 0.45rem; }

/* Every seat-axis chart on the page runs left to right, in both languages.
 *
 * This is a consistency rule before it is a typographic one. The chamber does
 * not mirror -- it is a seating plan, and the Knesset's benches do not swap
 * ends when a reader switches language -- so a bar chart of the same 120 seats
 * that *did* mirror would leave two charts describing one thing and pointing
 * opposite ways. Left to itself that is exactly what happened: the composition
 * bars stayed put because they are positioned with a physical `left`, while
 * the strips and the coalition track followed the writing direction, and the
 * page ended up with three seat axes in three directions.
 *
 * The labels inside these charts still read right to left; only the axis is
 * pinned. */
[dir="rtl"] .comp-track,
[dir="rtl"] .comp-seg,
[dir="rtl"] .comp-majority,
[dir="rtl"] .coal-track,
[dir="rtl"] .coal-majority,
[dir="rtl"] .strip { direction: ltr; }

[dir="rtl"] .comp-seg span { direction: rtl; }


/* What is currently picked out, named.
 *
 * Hover has a browser tooltip behind it and touch has nothing at all, so a
 * one-seat list could be highlighted in the chamber with its name shown
 * nowhere on the page. The line keeps its height when idle -- it holds the
 * hint that the linking exists at all, which was otherwise undiscoverable --
 * so naming a list never moves the chart under the finger that tapped it. */
.readout {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 1.6rem;
  margin: 0.6rem 0 0;
  font-family: var(--display);
  font-size: 0.88rem;
  color: var(--muted);
}

.readout .swatch { flex: none; }
.linked .readout { color: var(--ink); font-weight: 600; }


/* ---- disclosure -------------------------------------------------------- */

/* A block a reader opens, drawn as the heading it stands in for.
 *
 * The summary carries the same eyebrow treatment as `.trend-table-head`
 * because that is what it replaces: shut, the page should read as though the
 * heading is simply there and the content under it has not been reached yet.
 * A control that announced itself as a control -- a button, a box, a word
 * like "expand" -- would put a second kind of furniture on a page whose whole
 * layout is headings and rules.
 *
 * The marker points down and turns up, rather than pointing across and
 * turning down, so it means the same thing in Hebrew as in English. The
 * native triangle is removed for the same reason: it is drawn on the physical
 * left in both directions. */
.disclosure { margin: 2rem 0 0; }

.disclosure > summary {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  width: fit-content;
  cursor: pointer;
  list-style: none;
  font-family: var(--display);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  padding-block: 0.25rem;
}

.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary:hover { color: var(--ink); }

.disclosure-mark {
  flex: none;
  width: 12px;
  height: 12px;
  transition: transform 140ms ease;
}

/* Keyed off the element rather than off `.disclosure`, so the mark means the
   same thing wherever it is used -- the section rail is a `<details>` too. */
details[open] > summary .disclosure-mark { transform: rotate(180deg); }

.disclosure-body { margin-block-start: 0.6rem; }

@media (prefers-reduced-motion: reduce) {
  .disclosure-mark { transition: none; }
}

/* Hebrew drops the tracking and the uppercasing, the same way every other
   element in the mono/eyebrow role does. */
[lang="he"] .disclosure > summary { text-transform: none; letter-spacing: 0; font-size: 0.85rem; }


/* ---- the electoral threshold ------------------------------------------- */

/* Seats against share of the vote, and the whole point of it is a hole: the
 * counts between nought and the floor are a region of the plane the rule does
 * not reach. So the figure is drawn in one ink and one accent rather than in a
 * palette. There are only two classes of mark and they are already a plot's
 * height apart -- everything that missed is on the floor, everything that
 * cleared is at the floor of the Knesset or above -- so hue here is a second
 * telling of something position has already said, and a second telling is
 * exactly as much colour as it should get.
 *
 * The accent is `--alert`, and not because missing the line is a misfortune:
 * it is the hue this site already draws the seat floor in, on the per-list
 * trend cells, so a reader who has met one has met the other.
 */

.threshold-plot {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
  /* A share of the vote runs from less to more left to right in both
     languages. It is a scale, not a sentence: the same reason the chamber is
     not mirrored. */
  direction: ltr;
}

.threshold-grid { stroke: var(--rule); stroke-width: 1; }

/* The counts the step leaps over. A wash and not an outline -- an outline
   would draw it as a shape with something in it, and it is empty. */
.threshold-gap { fill: var(--ink); fill-opacity: 0.055; }

/* The threshold. Dashed for the same reason the trend's dissolution mark is:
   it divides the axis into two kinds of outcome rather than ending it. */
.threshold-rule {
  stroke: var(--alert);
  stroke-width: 1.4;
  stroke-dasharray: 4 4;
  fill: none;
  opacity: 0.75;
}

.threshold-rule-label { fill: var(--alert); font-weight: 600; }

/* Filled and stroked, at a fill weak enough to stay a region and an edge firm
   enough to be followed. Where every election agrees the two edges coincide
   and what is left is the stroke, which is the honest drawing of a band with
   no width. */
.threshold-band {
  fill: var(--ink);
  fill-opacity: 0.14;
  stroke: var(--ink);
  stroke-width: 1.6;
  stroke-linejoin: miter;
}

/* The leap itself, over the band's own edge. It is the one segment of the
   path that is not horizontal and it is the figure's whole subject. */
.threshold-jump { stroke: var(--ink); stroke-width: 3; fill: none; }

/* A ring of the surface, so two lists that took the same share of the same
   election stay two marks. */
.threshold-dot { stroke: var(--surface); stroke-width: 0.9; }
.threshold-dot.cleared { fill: var(--ink); }
.threshold-dot.missed { fill: var(--alert); fill-opacity: 0.9; }

/* 12.5px in a 1000-unit viewBox, which is what `charts.THRESHOLD_AXIS_SIZE`
   measures the notes against. The pair is held together by
   `tests/test_threshold_figure.py`. */
/* `--mono`, for the reason set out beside `.band-label`: `charts.py` measures
   these notes with `typography.text_width` to centre them and to decide
   whether the gap note fits at all, and that model charges Plex Mono's space.
   The face stays where the model is until both move together. */
.threshold-axis {
  font-family: var(--mono);
  font-size: 12.5px;
  fill: var(--muted);
}

.threshold-gap-note { fill: var(--ink); }
.threshold-votes { fill: var(--muted); }

/* The plot is pinned left-to-right, and these two are the only things in it
   that are sentences rather than scale marks. A Hebrew sentence laid out in an
   LTR paragraph has its leading numeral moved to the far end -- `3.25% היו
   136,854 קולות` read with the 3.25% last -- so the runs take the page's
   direction back. Both are set `text-anchor="middle"`, which is what lets them
   do that without moving: an anchored end grows away from its coordinate in
   whichever direction the text runs, and a middle does not. */
[dir="rtl"] .threshold-gap-note,
[dir="rtl"] .threshold-votes { direction: rtl; }

/* Two layouts of one relationship, not one scaled twice. The switch is at the
   width the trend switches at and for the same reason: the narrowest the
   content column ever gets is at 901px, one pixel above the width at which
   the rail stops sitting beside the figure. */
.threshold-narrow,
.threshold-drops { display: none; }

.threshold-narrow { max-width: 460px; margin-inline: auto; }

@media (max-width: 1180px) {
  .threshold-wide { display: none; }
  .threshold-narrow { display: block; }
  .threshold-drops { display: block; }
}

.threshold-drops {
  font-size: 0.82rem;
  color: var(--muted);
  margin: 0.75rem 0 0;
}

.threshold-key-head {
  font-family: var(--display);
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin: 1.6rem 0 0.6rem;
}

.threshold-legend {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: 0.65rem 2rem;
  margin: 0 0 1.4rem;
  padding: 0;
  list-style: none;
}

.threshold-legend li {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  font-size: 0.82rem;
  color: var(--muted);
}

.threshold-swatch {
  flex: none;
  width: 48px;
  height: 20px;
  overflow: visible;
  direction: ltr;
}

.threshold-table { width: 100%; border-collapse: collapse; font-size: 0.84rem; }

.threshold-table th,
.threshold-table td { padding: 0.45rem 0.75rem; border-bottom: 1px solid var(--rule); vertical-align: baseline; }

.threshold-table th {
  font-family: var(--display);
  font-size: 0.66rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  text-align: start;
  border-bottom-color: var(--ink);
}

.threshold-table th.num { text-align: end; }
.threshold-table td .num,
.threshold-table td .mono-ltr { display: block; font-size: 0.76rem; color: var(--muted); }

.threshold-th-note {
  display: block;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  opacity: 0.85;
}

/* A `<caption>`, not a paragraph above the table: it is the table's own
   accessible name, and this table is the figure's equivalent for a reader who
   cannot use the figure. */
.threshold-table-note {
  caption-side: top;
  text-align: start;
  font-size: 0.82rem;
  color: var(--muted);
  margin: 0 0 0.9rem;
  max-width: 52ch;
}

/* Below this the row stops being a row, the same way the trend's does and at
   the same width -- six columns and an election name do not fit in 390px. */
@media (max-width: 640px) {
  .threshold-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .threshold-table tr {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem 0.9rem;
    padding: 0.8rem 0;
    border-bottom: 1px solid var(--rule);
  }
  .threshold-table td { border: 0; padding: 0; text-align: start; }
  .threshold-table td:first-child {
    grid-column: 1 / -1;
    font-family: var(--display);
    font-weight: 600;
  }
  .threshold-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-family: var(--display);
    font-size: 0.6rem;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
  }
}

/* Hebrew drops the tracking and the uppercasing in the mono/eyebrow role,
   the same way every other element in it does. */
[lang="he"] .threshold-key-head,
[lang="he"] .threshold-table th { text-transform: none; letter-spacing: 0; font-size: 0.85rem; }
[lang="he"] .threshold-table th { font-size: 0.72rem; }
