/* 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;
}

/* ---- 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);
  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);
  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. */
.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;
  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-start: 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;
}
/* 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; }

@media (max-width: 640px) {
  .comp-row { grid-template-columns: 1fr 2.5rem; }
  .comp-name { grid-column: 1 / -1; }
}

@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); font-size: 0.78rem; color: var(--muted); }

/* ---- 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.median { 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);
}



/* ---- 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; }

[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; }
