/* The public site.
 *
 * Requires tokens.css and components.css, and adds nothing to them: the
 * chamber, the composition bars and the coalition builder here are the same
 * components the back office renders, from the same `charts.py`.
 *
 * The layout departs from the back office in one way that matters. This is a
 * publication, so the page is a column of prose that figures break out of,
 * rather than a grid of panels. There are no cards: sections are separated by
 * a heading and a rule, which is how a printed page has always done it and
 * what stops a reading page looking like a dashboard.
 */

/* ---- chrome ------------------------------------------------------------ */

/* The campaign picture bleeds out of the article it sits in, and the only
   width a child can name for the window is `vw`, which counts the scrollbar.
   `clip` and not `hidden`: `hidden` would make this a scroll container and
   the masthead's `position: sticky` would stick to it instead of to the
   window. Nothing on this site scrolls sideways as a page -- the wide tables
   scroll inside `.scroll` -- so there is nothing here to clip away. */
body { overflow-x: clip; }

/* The one colour the publisher is allowed, in both palettes.
 *
 * It was the footer's private `--foot-accent` until the masthead needed the
 * same `.ai` in the same orange; two copies of a brand colour is how the two
 * ends of a page drift apart. The light value is the aurora's orange darkened
 * until it clears 7:1 on white -- #ffab63 reads at 1.6:1 there and would have
 * been a decorative colour pretending to be a link. It clears 6.6:1 on the
 * masthead's slightly darker ground, which is the same claim. */
:root { --brand-accent: #8a3f08; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --brand-accent: #ffab63; }
}

:root[data-theme="dark"] { --brand-accent: #ffab63; }

/* Draws nothing: it carries the clip path both marks are cut from, and has to
   be out of flow so an empty SVG cannot open the page with a blank line. */
.brand-defs {
  position: absolute;
  inline-size: 0;
  block-size: 0;
  overflow: hidden;
}

.pub-head {
  position: sticky;
  top: 0;
  z-index: 20;
  background: color-mix(in oklab, var(--ground) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--rule);
}

/* The masthead grows with the window, because what is under it now does.
 *
 * A full-bleed painting the height of the viewport under a 57px masthead makes
 * the masthead read as a browser toolbar rather than as the publication's own
 * front. So every item in the row is fluid rather than stepped, and every one
 * of them is `clamp(<what it was>, <base> + <n>vw, <what it becomes>)`: the
 * floor is today's value and is reached at 1000px, which is where the masthead
 * starts giving things up anyway, so **nothing below 1000px changes size at
 * all** and the four narrow bands are exactly as they were measured. The
 * ceiling is reached at 1800px, so the masthead is bounded and a 4K window
 * gets the same masthead as a 1800px one.
 *
 * The controls grow too, and that is not decoration. `--head-h` is only safe
 * while the publisher's mark is not the tallest thing in this row -- see
 * `test_the_mark_is_shorter_than_the_row_it_joined` -- and the mark grows the
 * most of anything here. The language pill has always been the tallest item;
 * it has to stay that way. */
.pub-head-inner {
  width: min(var(--page), 100% - 3rem);
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 2rem;
  padding-block: clamp(0.85rem, 0.225rem + 1vw, 1.35rem);
}

.wordmark {
  font-family: var(--display);
  font-variation-settings: "wdth" 112;
  font-weight: 700;
  font-size: clamp(1.02rem, 0.67rem + 0.56vw, 1.3rem);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
}

/* Three renderings of one name: the full title, `short_name` for the widths
   where the full one cannot share a row with the controls, and `compact_name`
   for the phone. The narrow bands below swap them; a masthead on two lines
   reads as a mistake, and the swaps are what keep every width to one. */
.wordmark-short,
.wordmark-compact { display: none; }

.pub-nav { display: flex; gap: 1.5rem; }

.pub-nav a {
  font-size: clamp(0.92rem, 0.795rem + 0.2vw, 1.02rem);
  text-decoration: none;
  color: var(--muted);
  padding-bottom: 3px;
  border-bottom: 2px solid transparent;
}

.pub-nav a:hover { color: var(--ink); }
.pub-nav a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--bloc-a); }

/* The publisher's mark, at masthead size.
 *
 * The footer's lockup is 100px of aurora-filled silhouette beside a 2rem name,
 * and it earns that by closing the page. This is the same two pieces at a
 * fifth of the size and it is a different object: what survives the reduction
 * is the silhouette and the orange in it, not the crescent tail or the leaf
 * vein, so the mark here is read as a shape with weather in it. Stacking the
 * name under it -- the arrangement the footer could afford -- would leave
 * about 8px for the name inside a 29px row, so the lockup lies down.
 *
 * `--head-h` is the reason it is capped rather than merely small: the tallest
 * thing in this row is the language pill, and a brand taller than that would
 * move every sticky heading on the site. The cap is a moving one now, because
 * the masthead is fluid: the mark grows more than anything else in the row --
 * 1.35rem to 2.1rem -- and the pill is grown alongside it precisely so that it
 * stays the taller of the two at every width the clamp passes through.
 *
 * `site.name` and this name grow together and keep their ratio: the title is
 * uppercase, 700, in the site's own grotesque and this is lowercase, 500, in
 * the wordmark face, grey until it is hovered.
 * A byline, not a co-headline. */
.masthead-brand {
  display: flex;
  align-items: center;
  gap: 0.42rem;
  flex: none;
  text-decoration: none;
  color: var(--muted);
  /* One Latin object. It keeps its internal order on a Hebrew page -- mark,
     then name -- and only the box moves to the right-hand end. */
  direction: ltr;
}

.masthead-mark {
  display: block;
  block-size: clamp(1.35rem, 0.4125rem + 1.5vw, 2.1rem);
  inline-size: auto;
  flex: none;
}

.masthead-word {
  font-family: var(--wordmark);
  font-weight: 500;
  font-size: clamp(0.74rem, 0.465rem + 0.44vw, 0.96rem);
  /* The footer sets the name at 2rem and tightens it; at a third of that the
     letters need the space back rather than less of it. */
  letter-spacing: 0.01em;
  line-height: 1;
  white-space: nowrap;
}

.masthead-brand .brand-tld { color: var(--brand-accent); }
.masthead-brand:hover { color: var(--ink); }
.masthead-brand:hover .masthead-word { text-decoration: underline; text-underline-offset: 3px; }

/* The row's one auto margin, and it lives here rather than on the brand for a
   reason the brand cannot fix. `.masthead-brand` declares `direction: ltr` so
   the Latin lockup keeps mark-then-name on a Hebrew page, and a logical margin
   resolves against the element's own direction -- so `margin-inline-start` on
   it was `margin-left` in both languages while the row flipped underneath.
   English opened the empty half before the mark, Hebrew opened it after, and
   the publisher sat at opposite ends of the two mastheads.

   `.pub-controls` inherits the page's direction, so its start is the row's
   start in either one. The controls and the brand travel together to the far
   end, in that order, and the masthead flips whole. */
.pub-controls { display: flex; align-items: center; gap: 0.6rem; margin-inline-start: auto; }

.lang-switch { display: flex; border: 1px solid var(--rule); border-radius: 999px; overflow: hidden; }

/* The pill and the toggle carry the row's height, which is why they grow with
   it: they are the tallest items in the masthead and they have to stay taller
   than the publisher's mark, which grows faster than they do. Floors are
   today's values, reached at 1000px, so the narrow bands are untouched. */
.lang-switch a {
  font-family: var(--mono);
  font-size: clamp(0.72rem, 0.595rem + 0.2vw, 0.82rem);
  padding-block: clamp(0.3rem, 0.05rem + 0.4vw, 0.5rem);
  padding-inline: 0.7rem;
  text-decoration: none;
  color: var(--muted);
}

.lang-switch a[aria-current="true"] { background: var(--ink); color: var(--ground); }
.lang-switch a:not([aria-current]):hover { color: var(--ink); }

/* An icon, not a word. The button used to spell its mode out -- "theme:
 * auto" -- which cost 90px of row for a control most readers touch once. The
 * three SVGs are all in the document and `data-mode` picks one: a sun for
 * light, a moon for dark, a half-filled circle for following the system.
 * The accessible name still says the mode in full, in the page's language,
 * from the `data-label-*` attributes the template wrote.
 *
 * `font-size` stays on the button although it draws no text: the icon is
 * sized in `em` so one clamp -- the same one the language pill uses -- grows
 * both controls together, and the pill stays the taller of the two. */
.pub-controls .theme-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(0.72rem, 0.595rem + 0.2vw, 0.82rem);
  color: var(--muted);
  background: transparent;
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding-block: clamp(0.3rem, 0.05rem + 0.4vw, 0.5rem);
  padding-inline: 0.55rem;
  cursor: pointer;
}

.pub-controls .theme-toggle:hover { color: var(--ink); border-color: var(--ink); }

.theme-icon { display: none; inline-size: 1.18em; block-size: 1.18em; }

.theme-toggle[data-mode="system"] .theme-icon-system { display: block; }
.theme-toggle[data-mode="light"] .theme-icon-light { display: block; }
.theme-toggle[data-mode="dark"] .theme-icon-dark { display: block; }

/* The nav, folded behind three lines. Only where the row cannot hold the
 * links inline -- the wide masthead keeps `.pub-nav` and never shows this.
 * A `<details>`, not a scripted button, so it opens for the reader whose
 * JavaScript never arrived: the same reader the `--head-h` bands exist for.
 *
 * The panel hangs from the summary's box, `inset-inline-end: 0`, so it grows
 * away from the page edge in both languages without naming a side. */
.nav-menu { display: none; position: relative; }

.nav-menu summary {
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(0.72rem, 0.595rem + 0.2vw, 0.82rem);
  color: var(--muted);
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding-block: clamp(0.3rem, 0.05rem + 0.4vw, 0.5rem);
  padding-inline: 0.55rem;
  cursor: pointer;
}

.nav-menu summary::-webkit-details-marker { display: none; }
.nav-menu summary svg { inline-size: 1.18em; block-size: 1.18em; }
.nav-menu summary:hover,
.nav-menu[open] summary { color: var(--ink); border-color: var(--ink); }

.nav-menu-panel {
  position: absolute;
  inset-block-start: calc(100% + 0.6rem);
  inset-inline-end: 0;
  z-index: 30;
  min-inline-size: 10.5rem;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: 14px;
  padding: 0.4rem;
  box-shadow: 0 14px 34px -14px rgb(0 0 0 / 0.5);
}

.nav-menu-panel a {
  padding: 0.55rem 0.85rem;
  border-radius: 9px;
  text-decoration: none;
  color: var(--muted);
  font-size: 0.98rem;
}

.nav-menu-panel a:hover { color: var(--ink); }
.nav-menu-panel a[aria-current="page"] {
  color: var(--ink);
  border-inline-start: 2px solid var(--bloc-a);
  border-start-start-radius: 0;
  border-end-start-radius: 0;
}

/* A container, so that the full-bleed picture inside it can ask how wide the
   column it has broken out of actually is. That is the one measurement `vw`
   cannot give, because `vw` counts the scrollbar and this does not.
   `--poster-inset` below is the only thing that reads it. */
main { width: min(var(--page), 100% - 3rem); margin: 0 auto; container-type: inline-size; }

/* ---- the campaign poster ----------------------------------------------- */

/* The commissioned illustration, bled across the window under the masthead.
 * Which pages carry it is `webapp/poster.py`; this is only how it is drawn.
 *
 * Both pages that carry it lay a head over it, and neither lays the same one.
 * The forecast page takes three lines along the foot of a picture cropped to
 * two thirds of its height, because a page a reader came to for numbers
 * cannot spend five sixths of the window on a painting. The front page takes
 * its *entire* opening -- eyebrow, headline, three bloc figures, update line,
 * call, and the seat arc beside them -- onto the whole artwork at its own
 * shape, because there it is not a band above the page's opening, it is the
 * page's opening.
 *
 * So this runs in six parts: what is true of the picture on both pages, where
 * it sits, what is true of a head on it, each page's own head, and the bands
 * in which a head stops lying on the picture at all. */

/* How far in from the picture's edge a line has to start to stand on the
   page's own column. The head over the picture has to agree with `main`, or
   the page has two left edges.

   The picture is `100vw` and starts half a scrollbar outside the page, so the
   distance wanted is `(window - column) / 2` -- and `50cqi` is that column,
   measured off `main` itself rather than guessed from the window. Guessing is
   what this replaced: `max(1.5rem, 50vw - --page/2)` is exact only where the
   column has reached `--page`, and below that it names `main`'s 1.5rem gutter
   without the half-scrollbar the picture is already offset by. Seven or eight
   pixels of disagreement, everywhere a scrollbar takes room -- which is
   Windows and Linux, and not the machine this was drawn on.

   One expression and no bands: `main` narrows to `100% - 2rem` under 640 and
   this follows it there without being told, because it is not told the column,
   it asks. */
:root { --poster-inset: calc(50vw - 50cqi); }

/* The frame the head lies in: the painting alone, without the credit line
   under it. "The foot of the picture" has to mean the foot of the *painting*,
   and `.poster` is the picture *and* what is said about it.

   One cell, with the picture and the head both in it, and **not** a head
   positioned out of flow over a picture. That is the whole of the fix for a
   failure this branch has now had twice. An out-of-flow head cannot make the
   box it lies on any taller, so a head that outgrows its picture grows
   *upward* out of it -- and what is at the top of a head is its eyebrow. The
   first time, `.poster` clipped and the forecast page's "live forecast" label
   was simply not on the page. The second time the clip was one band up, in the
   crop; and where nothing clipped at all, the overflow painted underneath a
   masthead that is `sticky` at `z-index: 20`. Three ways to disappear, all of
   them tidy.

   In one cell the row is the taller of the two. A head with a line more than
   it has room for stops being a head with its top cut off and becomes a band
   of scrim below the painting, pushing the page down -- which is wrong, and
   wrong where a reader can see it. The headline is written per run, so this
   is a Tuesday rather than an edge case. */
.poster-frame {
  display: grid;
  /* The head lies along the foot of the painting. The picture keeps its own
     height rather than stretching to a row the head has made taller -- so the
     overflow appears under the picture, where the page grows, instead of
     silently recropping the artwork. */
  align-items: end;
  /* The scrim and the head are the only things stacked here, and they are
     stacked against each other rather than against the page. Without this
     they would join the page's stacking context and their `z-index` would be
     a claim about the masthead. */
  isolation: isolate;
}

.poster-frame > * { grid-area: 1 / 1; }

.poster img {
  display: block;
  width: 100%;
  align-self: start;
  /* The file's own aspect ratio decides the height, from the `width` and
     `height` on the element -- so the box is reserved before the image
     arrives and the page under it does not jump. The forecast page's crop
     declares a ratio on this element instead, which reserves the box just as
     well. A declared *height* would not, and there is none in these rules. */
  height: auto;
  border-block-end: 1px solid var(--rule);
}

/* On the page column, and it takes the reader's direction: it is text about
   the picture, not part of it. Padding rather than a narrower box, because the
   box is the picture's and the picture spans the window. */
.poster-credit {
  width: 100%;
  box-sizing: border-box;
  padding-inline: var(--poster-inset);
  /* It sat 0.6rem under the painting with the standfirst immediately under
     itself, so three voices ran together in one crowded stack. It needs air
     on both sides to read as the picture's caption rather than as the first
     line of the article. */
  margin: 1.15rem 0 0;
  text-align: start;
  font-family: var(--mono-label);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--muted);
}

/* ---- where the picture sits -------------------------------------------- */

/* Both pages draw it from inside `<main>` -- the front page at the top of
   `<main>` itself, the forecast page at the top of the article inside it --
   because on both a head lies over it, and that head carries the page's `h1`.
   See `base.html` for why the `h1` may not leave the landmark.

   Which means that on both it has to reach the window's edges from inside a
   centred column. A column-width picture on one of the two pages that carry
   it would read as a different picture.

   `50%` is half the box it is in, which is centred in the window, so the two
   margins reach the window's edges exactly. `50vw` would be half the window
   *including* the scrollbar and would overflow by half of it at either end --
   which is why `body` clips its inline overflow rather than scrolling it.

   These two selectors are also the only thing that tells the rest of this
   file which page it is looking at. There is no page class and there is no
   flag: the difference between the two heads *is* where the picture sits, and
   a class saying so a second time is a second thing to keep in agreement. */
.poster {
  margin-inline: calc(50% - 50vw);
  width: 100vw;
}

.article > .poster {
  /* The article is a grid, and above 1240px its first column is the section
     rail. Without this the picture would be centred on the rail rather than
     on the page, and `50%` would be half of a 13rem column. */
  grid-column: 1 / -1;
  /* The picture meets the masthead, so it takes back the space the article
     opens with. `<main>` opens with none, so the front page needs no such
     line. */
  margin-block-start: -3.5rem;
}

/* ---- the head over the picture ----------------------------------------- */

/* What is true of a head on the picture whichever page's head it is: it lies
 * in the painting's cell rather than over the page, it starts on the page's
 * own column, and its eyebrow is a broadcast bug rather than tinted type on a
 * painting.
 *
 * The scrim is a fixed dark in **both** palettes, and so is the type on it.
 * This is the foot of a dark painting, not a surface of the page: a themed
 * `--ground` would go near-white in the light palette and take the picture's
 * own bottom quarter with it, and `--ink` over it would then be dark type on
 * a photograph.
 *
 * So nothing in these blocks *reads* a palette token to paint with. Where the
 * front page needs one -- and it needs a dozen, because it puts whole
 * components of the site on the picture rather than three lines of type -- it
 * redefines them for the subtree instead. See that block. */
.poster-frame .poster-head {
  /* In the cell, over the picture, and painted after it. A grid item takes a
     `z-index` without being positioned, which is the point: it is in flow, so
     it can make the row taller. */
  z-index: 2;
  padding-inline: var(--poster-inset);
}

/* The eyebrow as a broadcast bug: a solid block rather than tinted type on a
   painting, which is what makes it legible over whatever the picture happens
   to be doing under it. Fixed pair for the same reason as the scrim -- a
   themed `--ground` would go near-white in the dark palette and take its own
   text with it. `box-decoration-break` so a label that wraps keeps a box on
   each line instead of one ragged L.

   One rule for the two names the two pages give the same mark: the forecast
   page's `.kicker` and the front page's `.eyebrow` are the same object doing
   the same job over the same painting, and the second copy of a rule is the
   copy that drifts. */
.poster-head .kicker,
.poster-head .eyebrow {
  display: inline-block;
  margin-inline-end: auto;
  margin-block-end: 0.55rem;
  padding: 0.34rem 0.6rem 0.3rem;
  background: #fff;
  color: #101619;
  font-weight: 500;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Hebrew in the mono role falls through IBM Plex Mono, which has no Hebrew,
   to Assistant -- a grotesque that at 500 is thinner than the Latin it stands
   in for, and thinner still inside a white block meant to read as one solid
   mark. `tokens.css` already steps every other Hebrew label in this role up
   for the same reason; this is that step, plus the weight.

   The family used to be named here too, because the space between the two
   words was coming from Plex Mono while the letters came from Assistant. That
   is now `--mono-label`'s job for every label on the site, this chip included,
   so the family is gone from this rule and only the chip's own two -- weight
   and size -- are left. */
[lang="he"] .poster-head .kicker,
[lang="he"] .poster-head .eyebrow {
  font-weight: 700;
  font-size: 0.78rem;
  padding-block: 0.28rem 0.24rem;
}

/* ---- the opening, on the picture ---------------------------------------- */

/* The whole opening, not a band above it. The picture keeps the artwork's own
 * 3:2 here -- the opening needs the room, and this is the front page's first
 * object rather than a strip over an article.
 *
 * In two shapes, and the second of them is a phone. The arrangement below is
 * the wide one: a landscape picture with the opening lying along its foot.
 * Held upright, that picture is 260px tall and the opening is 465, so there
 * is no foot to lie along -- which is why a phone used to get the picture as
 * a band and the opening under it, on the page's own ground, as two objects.
 * The phone band at the end of this section makes it one object again by
 * changing which of the two the reader is looking at: the picture stops being
 * the box the opening lies in and becomes the top of a poster whose lower
 * half is type on the artwork's own black.
 *
 * The palette is the interesting part. The forecast page puts three lines of
 * type on the scrim and can spell every one of their colours as a fixed pair.
 * This puts *components* there -- the seat arc, three bloc swatches, the
 * site's own call-to-action button, and whatever a focus ring is drawn in --
 * and every one of them is drawn from `tokens.css`. In the light palette that
 * meant the arc's party steps shading toward black on a black scrim, the 61
 * rule in near-black at half opacity and therefore invisible, and the button
 * arriving as a dark pill on a dark painting.
 *
 * Restyling each of them one at a time is how that list stays incomplete. So
 * the head redefines the palette instead: inside it, the page is dark, in
 * both themes, because a painting at night is what it is standing on. Every
 * component then draws itself correctly without knowing where it is -- the
 * button becomes a light pill with dark type, its hover stays the site's own
 * teal, and the focus ring goes from 3.4:1 against the scrim in the light
 * theme to 7.9:1 in both.
 *
 * The values are `tokens.css`'s dark palette, with one exception, marked. */
/* The picture may not grow past the window it opens.
 *
 * The front page keeps the artwork's own 3:2, and on a wide desktop that is a
 * bigger number than anyone's screen: at 2000px the picture is 1333px tall, so
 * the opening lying along its foot -- headline, bloc figures, seat arc, the
 * call -- starts below the fold and the front page is a poster with nothing on
 * it. Reported from a 2000px window, where none of the opening was visible.
 *
 * So the picture is capped at the window minus the masthead above it, and
 * `object-fit: cover` spends the cap on the artwork's foot rather than
 * squashing it -- `50% 0` keeps the top edge, which is the constraint the crop
 * has honoured since it was first drawn.
 *
 * Unbanded, and that is a change: it used to be written inside the band that
 * lays the opening on the picture, as though it were part of that arrangement.
 * It is not. "A picture taller than the window shows the reader nothing but
 * painting" is true wherever the picture is the page's first object, and the
 * band below decides only where the *opening* goes. Written once, it also
 * holds in the state that band sends a short window to. It bites wherever the
 * artwork's 3:2 is taller than the window under the masthead, which is a wide
 * and short window and nothing else: a phone held upright is 260px of picture
 * in 844px of window and never comes near it.
 *
 * `var(--head-h)` is the masthead's height as *the stylesheet writes it down*,
 * not as the browser drew it. `section-nav.js` overwrites it with a
 * measurement, and that script ships with the rail, which is the forecast
 * page's -- the front page does not load it, so what is read here is the
 * band's own value. That value is deliberately the tall end of a ramp:
 * 5.3rem covers a masthead that measures 62.6px at 1161 and 82.5 from 1800 up.
 * So this subtracts up to 22px more than the masthead takes, which shortens
 * the picture and can only move the opening's foot further inside the window.
 * The band below is sized against the same number, so the two agree about a
 * masthead neither of them has measured.
 *
 * `svh` rather than `vh`: on a phone `vh` is the viewport with the browser
 * chrome retracted, which is a height the reader may never actually have. A
 * cap that lies about the window is not a cap.
 *
 * It is a maximum and not a height, so a short window shrinks the picture and
 * a tall one still stops at the artwork's own size. And it caps the *picture*,
 * not the frame: a head too big for its picture must still push the row taller,
 * which is the whole of what the grid above is for.
 *
 * From 1024px up the masthead is no longer in front of the picture -- the
 * picture starts at the top of the page and the masthead lies on it -- so the
 * room the picture has is the whole window, and `the picture under the
 * masthead` below writes the same arithmetic with a zero where this one has a
 * masthead. That is an override of the number and not of the rule: the claim
 * is still "a picture may not grow past the window it opens", and it is still
 * made in one place about the picture rather than about the frame. */
.poster img {
  max-block-size: calc(100svh - var(--head-h));
  object-fit: cover;
  object-position: 50% 0;
}

@media (min-width: 1161px) and (min-height: 870px) {
  .poster .poster-head {
    padding-block: 7rem 1.8rem;
    background: linear-gradient(
      to top,
      rgb(0 0 0 / 0.97) 26%,
      rgb(0 0 0 / 0.9) 45%,
      rgb(0 0 0 / 0.55) 68%,
      transparent
    );
    /* Inherited ink: `body` passes a computed colour down, so redefining
       `--ink` alone would not reach anything that does not name it. */
    color: #fff;

    --ground: #101619;
    --surface: #182126;
    --surface-sunken: #131b1f;
    --ink: #e8eef1;
    --muted: #a2b3be;
    /* The exception. Everywhere else a hairline just off the ground reads as
       a rule; over a painting the ground is not flat, and the dark palette's
       #2a3940 under the bloc figures disappeared into the crowd. This is the
       one value tuned for a picture rather than for a page. */
    --rule: rgb(255 255 255 / 0.4);
    --bloc-a: #3aada7;
    --bloc-b: #d69a3c;
    --bloc-c: #a988e0;
    --unaffiliated: #8697a6;
    --emblem-card: #f3f5f6;
    --emblem-edge: #f3f5f6;
    --alert: #e8776d;
    --majority: #e8eef1;
    --shade-toward: #ffffff;
  }

  /* The hero keeps its own two columns and its own type; what it gives up is
     the space it opened with, which the scrim's padding now provides. */
  .poster .poster-head .hero {
    gap: 2.5rem;
    padding: 0;
    border: 0;
  }

  .poster .poster-head h1 {
    /* The gradient carries most of the contrast; this is for the lines that
       ride up past it into the crowd. */
    text-shadow: 0 1px 14px rgb(0 0 0 / 0.55);
  }

  /* Uncapped, the arc grows with its half of the window and pushes the
     opening taller than the picture it is lying on. */
  .poster .poster-head .hero-chamber svg { max-height: 300px; }
}

/* ---- the opening, stacked ----------------------------------------------- */

/* Held upright there is no foot to lie along. The artwork is 1600x1067, so at
 * 390px of window it is 260px tall, and the opening it would have to carry is
 * 465px in Hebrew and 527 in English. The picture is not a box the opening can
 * sit in; it is smaller than the opening.
 *
 * There are two ways out and only one of them keeps the cast.
 *
 * The first is to crop the picture into a portrait box and put the opening on
 * it. `object-fit: cover` in a portrait box crops the *sides*, and what
 * survives is `box aspect / 1.5` of the artwork's width, centred -- 3:4 keeps
 * half of it. The half it keeps is the middle, and the middle is Netanyahu.
 * Worse, the opening then eats the box from the bottom: at 390 a 3:4 box is
 * 520px and the opening is 476 of it, so 44px of painting is left clear above
 * the type -- and at 320 the number is **zero**, in both languages, because
 * the headline takes six lines there and the box grows to hold them. The
 * whole painting under the scrim's falloff, at the smallest size we support,
 * with one face in the frame. That was drawn, screenshotted and rejected, and
 * rejected for the right reason.
 *
 * The second is to stop asking the picture to be the box. The picture is a
 * band across the top of a poster and the opening stands under it on the
 * poster's own ground -- the film-poster arrangement, where the art is a band
 * and the type is beneath it. The whole cast is in frame, nothing is under a
 * scrim, and the two are one object rather than a picture and a page.
 *
 * That is this band, and three things make it work.
 *
 * **The crop is 7:6, not none and not 3:4.** At the artwork's own shape the
 * band is 260px at 390 and every face is about 26px tall. 7:6 shows 78% of
 * the artwork's width -- every face in the cast lies inside the middle 73%,
 * so this has air on both sides of them -- and buys 28% more height for it:
 * 334px at 390, 274 at 320, 369 at 430. What it gives up is the guard tower
 * and the tip of the crocodile's snout at the right edge, and the outer half
 * of the raised hand at the left.
 *
 * **The ground is #05090b, and it is not a palette token.** It is the
 * artwork's own bottom edge: the last three rows of the file average
 * (5, 9, 11) and no column of them is further than five levels from it. So
 * the seam where the picture stops is a colour meeting itself, which is why
 * there is no bridging trick in these rules and no hard edge in the render.
 * A themed ground would put the painting on white in the light palette and
 * the seam would be the loudest edge on the page.
 *
 * **The opening is pulled up 18vw over the picture's foot.** The picture is
 * 66.7vw tall, so 18vw is 27% of it whatever the phone -- the crowd and the
 * burning skyline along the bottom, which is the part of the artwork the
 * forecast page's crop throws away on purpose. The eyebrow lands on that,
 * 26px inside the paint at 390 and 14 at 320, and everything below it is on
 * the ground. Measured clear picture: 264px of 334 at 390, 217 of 274 at 320,
 * 291 of 369 at 430. The lowest face in the cast is Lapid's chin at 58% of
 * the artwork's height -- 194px, 159 and 214 at those three sizes -- so every
 * face clears the opening by 70px, 58 and 77, in both languages.
 *
 * The seat arc stays out of it. It is the third row, on the page's own
 * ground, in the page's own palette -- because the arc reads `--shade-toward`
 * and the pin below is on the opening rather than on the frame. On a dark
 * ground with the light palette's shading, the arc's steps shade toward black
 * on black; the desktop arrangement has the arc *on the painting* and inside
 * the pin, which is why this one is different rather than inconsistent. */
@media (max-width: 1160px), (max-height: 869px) {
  .poster {
    padding-block-end: 1.6rem;
    border-block-end: 1px solid var(--rule);
  }

  /* Two rows, and that is the whole of the change: the picture has a row of
     its own instead of sharing the opening's cell. The frame keeps the
     `isolation` and the `align-items: end` it is given above -- with
     content-sized rows neither has anything to do -- so what is written here
     is only the rows and where each thing goes in them. */
  .poster .poster-frame {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto;
  }

  /* The ground under the opening. It covers the second row exactly, which
     starts at the picture's foot -- the 18vw the opening is pulled up by is
     over the painting and must not be painted over. */
  .poster .poster-frame::after {
    content: "";
    grid-column: 1;
    grid-row: 2;
    align-self: stretch;
    z-index: 0;
    background: #05090b;
  }

  /* `object-fit: cover` and `object-position: 50% 0` are the picture's own,
     from the rule above this band; only the shape is new. The vertical half
     of that position is doing nothing here and is doing it correctly: a box
     more portrait than the source crops the sides and shows the whole height,
     and if the cap above ever does bite -- a 599px window under 400px tall --
     `0` keeps the top edge, which is the crop's standing constraint. */
  .poster .poster-frame > img {
    grid-column: 1;
    grid-row: 1;
    aspect-ratio: 7 / 6;
    border-block-end: 0;
  }

  /* The opening is the grid's second item rather than a box inside a box: the
     head and the hero are taken out of the way so that the opening and the
     arc can be placed in different rows, which is the whole reason the arc
     escapes the dark ground. */
  .poster .poster-head,
  .poster .poster-head .hero {
    display: contents;
  }

  .poster .hero-inner {
    grid-column: 1;
    grid-row: 2;
    z-index: 2;
    box-sizing: border-box;
    inline-size: 100%;
    max-inline-size: none;
    margin-block-start: -18vw;
    padding-inline: var(--poster-inset);
    padding-block: 2.75rem 1.5rem;
    /* Percentages of the opening, which is mostly on the ground -- so the
       peak under the type matters less than the falloff above it, and the
       falloff has to be out before it reaches the faces. Out at 92% of a
       465px opening is 37px, and the eyebrow starts 26px below that. */
    background: linear-gradient(
      to top,
      rgb(0 0 0 / 0.92) 0%,
      rgb(0 0 0 / 0.8) 40%,
      rgb(0 0 0 / 0.42) 70%,
      transparent 92%
    );
    color: #fff;

    --ground: #101619;
    --surface: #182126;
    --surface-sunken: #131b1f;
    --ink: #e8eef1;
    --muted: #a2b3be;
    --rule: rgb(255 255 255 / 0.4);
    --bloc-a: #3aada7;
    --bloc-b: #d69a3c;
    --bloc-c: #a988e0;
    --unaffiliated: #8697a6;
    --emblem-card: #f3f5f6;
    --emblem-edge: #f3f5f6;
    --alert: #e8776d;
    --majority: #e8eef1;
    --shade-toward: #ffffff;
  }

  .poster .hero-chamber {
    grid-column: 1;
    grid-row: 3;
    box-sizing: border-box;
    inline-size: 100%;
    padding-inline: var(--poster-inset);
    padding-block: 1.5rem 0;
  }

  /* The lines that ride up past the gradient into the crowd. */
  .poster .poster-head h1 {
    text-shadow: 0 1px 14px rgb(0 0 0 / 0.55);
  }

  /* The bloc row is not touched, and that is deliberate rather than an
     omission. It is a shared component and its own section says why: the two
     pages carry the same three numbers and a reader sees both a page apart,
     so a size that held on one of them only would read as two objects. On a
     phone it wraps two and one -- 464px of row against 358 of window at 390 --
     and it wraps that way on the forecast page too. What is wrong there is
     wrong in the component, not here. */
}

/* ---- the opening, stacked, wider than a phone --------------------------- */

/* The same two rows, at the widths that have room for a wider picture.
 *
 * The band above is written for a phone, where a portrait crop is the only
 * shape that leaves the cast legible at 390px. Above that the window is wide
 * enough that 7:6 would be enormous -- 943px of picture at 1100px of window --
 * so the crop opens out to the artwork's own 3:2, which is the one ratio that
 * crops nothing at all: the whole cast, every time, at every size in here.
 *
 * This band exists because there was a third arrangement before it, and it
 * was the wrong one: between 600 and 1160 the opening came *off* the picture
 * and stood under it, so a window at a perfectly ordinary laptop width opened
 * on a bare painting with the forecast somewhere below the fold. The head is
 * on the picture at every size now, which is what the two bands either side
 * of this always did.
 *
 * The pull is smaller in proportion for the same reason the crop is: 18vw of
 * a 1100px window is 198px of overlap, which would put the opening's top edge
 * a third of the way up the painting. */
@media (min-width: 600px) and (max-width: 1160px),
       (min-width: 600px) and (max-height: 869px) {
  .poster .poster-frame > img { aspect-ratio: 3 / 2; }
  .poster .hero-inner { margin-block-start: -10vw; }
}


/* ---- the picture under the masthead ------------------------------------ */

/* The masthead lies on the painting rather than above it, and the painting is
 * what a poster page opens with.
 *
 * This is what pays for the taller crop. A picture that starts under the
 * masthead spends the masthead's height twice -- once on the masthead and once
 * on the strip of painting it pushes down the page -- and the strip it pushes
 * down is the sky and the comet, which is the part of the artwork worth the
 * least. Started at the top of the page instead, the same crop costs the page
 * 105px at 2000 rather than 188, 64 rather than 135, and 59 rather than 128.
 * The difference in each is exactly the masthead: 83, 71 and 69 measured.
 *
 * Then the masthead has to stop being a lid. At the tint it wears over an
 * article -- 88% of the ground -- a painting behind it is a dark rectangle
 * with the publication's name in it, which is a worse thing than the crop it
 * bought. So on these pages it is a veil: the ground at 62% in the dark
 * palette and 78% in the light one, and the blur up from 10px to 16 with a
 * little saturation so what shows through reads as painting rather than as
 * noise.
 *
 * The two numbers are not a preference. Measured in Chrome over the strip of
 * this artwork the masthead actually covers -- sky, and the comet, which is
 * the brightest thing in it -- the masthead's own type reads at worst 5.71:1
 * in the dark palette and 9.51:1 in the light one, across both pages, both
 * languages and every width from 1024 to 2000. A *pale* veil over a dark
 * painting is where the near-black ink runs out first, and the light palette
 * at the dark one's open value measures 4.47:1, which is under AA by a hair.
 * That is why the light palette does not get the dark one's number.
 *
 * And then the veil has to stop being a veil, because it follows the masthead
 * down the page and there is nothing behind it below the picture except the
 * article. `animation-timeline: scroll()` thickens it back to 92% over the
 * first 60vh: transparent enough to show the painting where the painting is,
 * opaque before the lists table reaches it. It is a property of the picture
 * expressed on the masthead, which is why it is written as a scroll position
 * and not as a state. No script; `@supports` degrades it to the static veil
 * above, which is legible at both tints by the same measurements.
 *
 * `--veil-open` carries the palette's own starting tint into the keyframes,
 * so there is one animation rather than one per theme. The dark palette opens
 * further than it settles at -- 52 against 62 -- because it measures 7.85:1
 * there and can afford to. The light palette's two numbers are the same, so
 * in the light theme the scroll only closes the veil.
 *
 * Banded at 1024, which is the width the forecast page's crop starts at and
 * therefore the width at which any of this is about a picture with a head on
 * it. Below it the arrangement must not run at all: the phone masthead is one
 * row now, but the crop it would pull the picture into does not start until
 * 1024, and a picture pulled up under a head it does not have is a picture
 * with its top gone.
 *
 * The one cost, and it is a real one. `--head-h` is what the stylesheet
 * *writes down* for the masthead, and it is written deliberately long -- the
 * masthead is a ramp from 57.6px at 1001 to 84.5 at 1800 and this is 84.8
 * throughout. The forecast page loads `section-nav.js`, which replaces the
 * value with a measurement, so there the pull is exact; the front page loads
 * no script, so it over-pulls by what the guess is long by. Measured: 0 to
 * 2px at 2000, 12 to 13 at 1440, 14 to 16 at 1366, 19 to 21 at 1200 and 25 to
 * 26 at 1024. Those pixels are above the top of the document and cannot be
 * scrolled to, and every one of them is sky. The alternative was to take the
 * masthead out of flow on these pages, which needs no number at all and is a
 * larger change to a thing every page shares. */
@media (min-width: 1024px) {
  body.has-poster .poster {
    margin-block-start: calc(-1 * var(--head-h));
  }

  /* The article's own opening as well, which the picture was already taking
     back. */
  body.has-poster .article > .poster {
    margin-block-start: calc(-3.5rem - var(--head-h));
  }

  /* The cap is the window less whatever is above the picture, and above the
     picture there is now nothing. The unbanded value subtracts the masthead
     because below this band the masthead is still in front of it; here the
     same arithmetic has a zero in it. Both are the same claim -- a picture
     may not grow past the window it opens -- and the front page's opening
     lies along the foot of whichever of the two applies. */
  body.has-poster .poster img {
    max-block-size: 100svh;
  }

  body.has-poster .pub-head {
    --veil-open: 78%;
    background: color-mix(in oklab, var(--ground) 78%, transparent);
    backdrop-filter: blur(16px) saturate(1.1);
    border-block-end-color: transparent;
  }

  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) body.has-poster .pub-head {
      --veil-open: 52%;
      background: color-mix(in oklab, var(--ground) 62%, transparent);
    }
  }

  :root[data-theme="dark"] body.has-poster .pub-head {
    --veil-open: 52%;
    background: color-mix(in oklab, var(--ground) 62%, transparent);
  }

  @supports (animation-timeline: scroll()) {
    body.has-poster .pub-head {
      animation: masthead-settle linear both;
      animation-timeline: scroll();
      animation-range: 0 60vh;
    }
  }
}

@keyframes masthead-settle {
  from {
    background-color: color-mix(in oklab, var(--ground) var(--veil-open), transparent);
  }

  to {
    background-color: color-mix(in oklab, var(--ground) 92%, transparent);
  }
}

/* ---- the hero ---------------------------------------------------------- */

/* The front page opens on the forecast itself, because that is the most
   characteristic thing this publication has: not a photograph of a politician,
   but a sentence about a number and the number beside it. */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 3rem;
  align-items: center;
  padding: 4rem 0 3.5rem;
  border-bottom: 1px solid var(--rule);
}
.hero-inner { max-width: 38rem; }
.hero-chamber svg { width: 100%; height: auto; display: block; }

.eyebrow,
.kicker {
  font-family: var(--mono-label);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--bloc-a);
  margin: 0 0 1rem;
}

.hero h1 {
  font-family: var(--prose);
  font-variation-settings: "opsz" 60;
  font-size: clamp(2rem, 1.35rem + 2.4vw, 3.2rem);
  font-weight: 600;
  line-height: 1.06;
  letter-spacing: -0.02em;
  margin: 0 0 2rem;
  text-wrap: balance;
}

.hero-meta { font-family: var(--mono-label); font-size: 0.76rem; color: var(--muted); margin: 0 0 1.5rem; }

.cta {
  display: inline-block;
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  color: var(--ground);
  background: var(--ink);
  padding: 0.65rem 1.4rem;
  border-radius: 999px;
}

.cta:hover { background: var(--bloc-a); }

/* The arrow points the way the reader is going, so it is a property of the
   direction rather than a character in the markup. Bidi would have moved a
   literal `→` to the left of a Hebrew line and left it pointing right, which
   reads as "back". */
.cta::after { content: "\2192"; margin-inline-start: 0.5em; }
[dir="rtl"] .cta::after { content: "\2190"; }

/* ---- the three bloc figures -------------------------------------------- */

/* Seats, swatch, name, chance of 61 -- three times, on both pictures.
 *
 * It was `.hero-blocs` and it lived in the block above, because the front
 * page was the only page that stated the three totals in figures. The
 * forecast page carries the same row at the foot of its crop now, so the
 * name is no longer a claim about which page this is -- and the rules moved
 * out of the hero with it, because a shared component styled inside another
 * component's section is a component nobody remembers is shared.
 *
 * One set of values for both pages. The two rows are read a page apart by
 * the same reader and are the same three numbers, so a size or a rule that
 * held on one of them only would read as two different objects; what each
 * page adds is its own ground underneath, not its own row.
 *
 * `min-inline-size` rather than a track: the row is three cards of one line
 * each in English and Hebrew both, and the floor is what stops a two-word
 * bloc name from setting a card narrower than its own number.
 *
 * The swatch and the name are one flex line, which mirrors whole. Neither
 * carries a logical box property and neither pins its own direction, which
 * is what `hebrew-rtl-layout` section 1 is about -- an element that fixes its
 * own `direction` freezes `margin-inline-start` to a physical side and the
 * mark ends up at the wrong end of a Hebrew row. */
.bloc-figures { display: flex; flex-wrap: wrap; gap: 2.5rem; margin-bottom: 2rem; }

/* The margin separates the row from what comes after it, and on the forecast
   page nothing does -- the row is the last thing in the head, and 2rem of it
   landed on top of the head's own bottom padding as 57px of scrim under the
   last number. Written as a property of the row rather than as a rule for
   that page, because it is true of any page that ends its head here. */
.bloc-figures:last-child { margin-bottom: 0; }
.bloc-figures > div { padding-block-start: 0.6rem; border-block-start: 2px solid var(--rule); min-inline-size: 8rem; }
.bloc-figures b {
  display: block;
  font-family: var(--display);
  font-variation-settings: "wdth" 118;
  font-size: 2.8rem;
  font-weight: 700;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.bloc-figures span { display: flex; align-items: center; gap: 0.4rem; font-size: 0.9rem; margin-top: 0.35rem; }
.bloc-figures em {
  display: block;
  font-family: var(--mono-label);
  font-style: normal;
  font-size: 0.72rem;
  color: var(--muted);
  margin-top: 0.2rem;
}

/* Three across on a phone, which the floor and the gap were stopping.
   `min-inline-size: 8rem` and a 2.5rem gap need 464px of row before a bloc's
   name is even measured, and a phone has 358 at 390 and 288 at 320. So the
   row wrapped: two and one at 390 and 430, one and one and one at 320 --
   236px and 385px of head to say three numbers.

   Which is worth a rule rather than a shrug, because of what it says. A row
   of three blocs whose third is alone on a line under the other two is the
   two-bloc framing drawn instead of written -- the leading bloc and the
   runner-up together, and the Arab parties as a footnote to them. The row
   exists to stop exactly that.

   Tracks rather than wrapping, `minmax(0, 1fr)` and the floor off, because
   the floor is the thing that makes a track refuse to shrink. The type is not
   touched: it is the same row on both pages at every width, which is what the
   section above is about, and the numbers fit -- a two-digit seat count at
   2.8rem is 54px inside an 86px column at 320.

   One band, at the width the front page's opening becomes a poster. The row
   stops fitting nearer 496 by the arithmetic above, but that number is a
   lower bound -- a bloc name wider than 8rem raises it -- and a second number
   here is a second thing to keep in agreement with the first. */
@media (max-width: 599px) {
  .bloc-figures {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.9rem;
    margin-bottom: 1.4rem;
  }

  .bloc-figures > div { min-inline-size: 0; }
}

/* ---- the stream -------------------------------------------------------- */

.stream { padding: 3.5rem 0 4rem; }

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 2rem;
  padding-bottom: 0.9rem;
  border-bottom: 2px solid var(--ink);
  margin-bottom: 2.25rem;
}

.section-head h2 {
  font-family: var(--display);
  font-variation-settings: "wdth" 108;
  font-size: 1.05rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  margin: 0;
}

.section-head a {
  font-family: var(--mono-label);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  text-decoration: none;
}

.section-head a:hover { color: var(--ink); }

/* Asymmetric on purpose: the newest piece is the one being published, and a
   grid of equal tiles says nothing is more important than anything else. */
.stream-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2.5rem 2rem; }
.card.lead { grid-column: span 2; grid-row: span 2; }

.card a { text-decoration: none; color: inherit; display: block; }
.card h3 {
  font-family: var(--prose);
  font-variation-settings: "opsz" 28;
  font-size: 1.28rem;
  font-weight: 600;
  line-height: 1.22;
  margin: 0 0 0.5rem;
}
.card.lead h3 { font-size: 2rem; font-variation-settings: "opsz" 44; line-height: 1.12; }
.card a:hover h3 { color: var(--bloc-a); }
.card .dek { font-size: 0.92rem; color: var(--muted); margin: 0; line-height: 1.5; }
.card.lead .dek { font-size: 1.05rem; }
.card .meta { font-family: var(--mono-label); font-size: 0.7rem; color: var(--muted); margin: 0.75rem 0 0; }
.card .kicker { margin-bottom: 0.5rem; }

/* Bounded rather than proportional: the lead card is twice the width and
   twice the height of its neighbours, and a figure that scaled with it would
   arrive as a wall of colour with three shapes on it. */
.post-fig {
  display: block;
  width: 100%;
  height: 148px;
  background: var(--surface-sunken);
  border-radius: 3px;
  margin-bottom: 1rem;
  padding: 0.75rem;
}
.card.lead .post-fig { height: 208px; }
.article-figure .post-fig { height: 200px; }

/* ---- articles ---------------------------------------------------------- */

.article { padding: 3.5rem 0 5rem; max-width: var(--column); margin: 0 auto; }
.article.wide { max-width: none; }

/* The head opens under the picture's credit, so it carries its own air. */
.article-head { margin-bottom: 2.5rem; }
.article.wide > .article-head { padding-top: 2rem; }
.article-head h1 {
  font-family: var(--prose);
  font-variation-settings: "opsz" 54;
  font-size: clamp(2rem, 1.4rem + 2.2vw, 3rem);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.018em;
  margin: 0 0 1rem;
  text-wrap: balance;
  max-width: 24ch;
}
.article.wide .article-head h1 { max-width: 30ch; }
.article-head .dek {
  font-family: var(--prose);
  font-variation-settings: "opsz" 18;
  font-size: 1.2rem;
  line-height: 1.5;
  color: var(--muted);
  margin: 0 0 2rem;
  max-width: 54ch;
}
.article-head .meta {
  font-family: var(--mono-label);
  font-size: 0.7rem;
  color: var(--muted);
  margin: 0;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
}

/* Provenance: the note and the stamp it refers to, in one block.
   The band under the picture used to run five type styles and three
   separators -- a mono credit, a serif standfirst, a rule, a second mono at
   a different size, a bordered note in the body face, and the run id in a
   third. It is two faces now: the prose face for the two sentences a reader
   reads, the label face at one size for the two lines of apparatus, under a
   single rule rather than a rule and a coloured border. */
.provenance { border-top: 1px solid var(--rule); padding-top: 1.15rem; }
.provenance p { margin: 0; }
.provenance .note {
  font-family: var(--prose);
  font-variation-settings: "opsz" 15;
  font-size: 0.95rem;
  line-height: 1.6;
  color: var(--muted);
  max-width: 58ch;
}
.provenance .stamp {
  margin-top: 0.8rem;
  font-family: var(--mono-label);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.provenance .run-id { font-family: var(--mono); letter-spacing: 0; }

.article-figure { margin-bottom: 2.5rem; }


.prose { font-family: var(--prose); font-variation-settings: "opsz" 15; font-size: 1.12rem; line-height: 1.68; }
.prose p { margin: 0 0 1.25rem; }
.prose h2 {
  font-family: var(--prose);
  font-variation-settings: "opsz" 30;
  font-size: 1.5rem;
  font-weight: 600;
  line-height: 1.2;
  margin: 2.75rem 0 0.9rem;
  letter-spacing: -0.01em;
}
.prose strong { font-weight: 700; }
.prose a { color: var(--bloc-a); text-underline-offset: 3px; }
.prose table { width: 100%; border-collapse: collapse; font-family: var(--body); font-size: 0.92rem; margin: 1.75rem 0; }
.prose th {
  text-align: start;
  font-family: var(--mono);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  padding: 0 0.7rem 0.5rem;
  border-bottom: 1px solid var(--rule);
}
.prose td { padding: 0.5rem 0.7rem; border-bottom: 1px solid var(--rule); }
.prose td:not(:first-child), .prose th:not(:first-child) { text-align: end; font-variant-numeric: tabular-nums; }

/* A reference inside the article's own prose, leaving the site. The threshold
   section is the first place the forecast page has one -- it names two
   allocation rules and links each once -- so this is the convention rather
   than a description of one:

     * the same colour and underline a link in a post body already gets, so a
       reader who has read an analysis piece recognises it;
     * `rel="noopener"` and no `target`, matching the site's other outbound
       links in the masthead and the footer. It opens in place, and a reader
       who wants a second tab has the modifier for it;
     * no external-link glyph, because nothing else on the page carries one.

   Matched on the href rather than on a class: the anchors come out of the
   string tables, and a class name is not something a translator should have
   to carry. Internal markers -- the table's dagger, the section rail -- are
   fragments and paths, so they are not caught by this. */
.article-body a[href^="http"] { color: var(--bloc-a); text-underline-offset: 3px; }

.article-back { margin-top: 3.5rem; padding-top: 1.5rem; border-top: 1px solid var(--rule); }
.article-back a { font-family: var(--mono-label); font-size: 0.78rem; color: var(--muted); text-decoration: none; }
.article-back a:hover { color: var(--ink); }

/* Figures break out of the reading column rather than being squeezed into it. */
.breakout { margin-bottom: 3.5rem; }
.article-body > .plate.breakout { padding-top: 2.25rem; border-top: 1px solid var(--rule); }
.plate .rail h2 {
  font-family: var(--display);
  font-variation-settings: "wdth" 104;
  font-size: 0.85rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  margin: 0 0 0.75rem;
}

table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
th {
  text-align: start;
  font-family: var(--mono);
  font-size: 0.7rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  padding: 0 0.75rem 0.6rem;
  border-bottom: 1px solid var(--rule);
  white-space: nowrap;
}
td { padding: 0.55rem 0.75rem; border-bottom: 1px solid var(--rule); }
tbody tr:last-child td { border-bottom: none; }
.num { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: end; }

/* A cell whose content is a number inside a sentence -- "up to 11", "66 of
   100" -- rather than a bare figure.
 *
 * It cannot use `.num`, which pins LTR in Hebrew (see `tokens.css`). That is
 * right for a figure or a range, which are Latin-ordered tokens in any
 * language, and wrong for a sentence: pinned LTR, "66 מתוך 100" rendered with
 * both numbers on the left and the word after them, so it read as "out of 100
 * 66". Everything else `.num` does -- the mono face, tabular figures, aligned
 * to the far edge of the column -- it still wants. */
.num-prose { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: end; }
.scroll { overflow-x: auto; }
.empty { color: var(--muted); padding: 3rem 0; }

/* ---- footer ------------------------------------------------------------ */

/* ---- footer ------------------------------------------------------------
 *
 * The one place on the site that is dark in both themes, and the only place
 * with a photograph in it. That is deliberate on both counts: the forecast
 * pages are an instrument and stay quiet, so the page needs somewhere to
 * close, and a single high-contrast slab does more for the whole document
 * than colour spread thinly through it would.
 *
 * Its palette is fixed rather than themed. A footer that inverted with the
 * theme would be a second surface competing with the content above it in
 * light mode and invisible against the page in dark mode; pinning it means it
 * reads as the same object in both.
 */

/* The footer follows the theme.
 *
 * It used to be pinned dark in both, on the argument that it then read as the
 * same object whichever palette the reader chose. Against a white page that
 * argument loses: a near-black slab meeting a light document is a hard edge
 * that reads as a rendering seam rather than as a decision, and no amount of
 * shadow under it makes a reader believe the page was designed that way.
 *
 * So there are two footers, and the cost is accepted: the brand's ground is
 * not one colour. What stays constant is everything that carries meaning --
 * the wash, the grain, the lockup, the ordering -- and those are what a reader
 * recognises.
 *
 * Light is the default here because `:root` is light in `tokens.css`; the two
 * dark selectors below mirror the pattern that file establishes.
 */
.pub-foot {
  --foot-ground: #ffffff;
  --foot-ink: #16202b;
  --foot-muted: #4a5764;
  --foot-rule: rgba(22, 32, 43, 0.14);
  /* The brand accent is defined once, up in the chrome section, because the
     masthead wears it too. Not a bloc colour: those mean a specific bloc
     everywhere else on the site, and a commercial link is not a bloc. */
  --foot-accent: var(--brand-accent);

  /* Grain over a pale ground has to darken; over a dark one it has to lift. */
  --grain-ink: #6b7a85;
  --grain-blend: multiply;
  --grain-opacity: 0.22;

  /* The alphas that make the aurora visible without turning pastel. */
  --wash-warm: rgba(252, 120, 56, 0.2);
  --wash-mid: rgba(195, 136, 139, 0.14);
  --wash-cool: rgba(61, 167, 189, 0.12);

  margin-top: 4rem;
  background: var(--foot-ground);
  color: var(--foot-ink);
  position: relative;
  isolation: isolate;
  overflow: hidden;
  /* A plain hairline, the same one the footer uses between its own rows. The
     aurora used to run across here as a 3px band; now that it is the wash
     behind the whole slab, a second one at the top edge was two of the same
     gesture arguing. The change of ground is what separates footer from page
     -- this only says where it begins. */
  border-top: 1px solid var(--foot-rule);
}

.pub-foot-inner {
  position: relative;
  width: min(var(--page), 100% - 3rem);
  margin: 0 auto;
  padding: 3.5rem 0 2.5rem;
  display: grid;
  /* Three columns of content and a fourth left empty: the watermark needs
     somewhere to be, and the alternative -- a column of text over it -- was
     the version where neither could be read. */
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 0.6fr) minmax(0, 0.8fr) minmax(0, 1.1fr);
  gap: 2.5rem 3rem;
  align-items: start;
}

/* Grid items default to min-width:auto, which lets a long word push a column
   wider than its track and the whole row past the viewport. */
.pub-foot-inner > * { min-width: 0; }

.foot-brand { display: flex; flex-direction: column; align-items: flex-start; gap: 0.9rem; }

.brand-lockup {
  display: flex;
  align-items: center;
  gap: 1rem;
  text-decoration: none;
  color: var(--foot-ink);
  /* The lockup is one Latin object and keeps its internal order on a Hebrew
     page: mark, then word. Only the box moves to the right-hand start. */
  direction: ltr;
}

.brand-mark {
  display: block;
  /* Sized to sit beside the wordmark rather than over it. At 148px the mark
     dominated a name that carries more of its own character now; at 100 the
     crescent tail and the leaf vein both still read, which is what breaks
     first in either direction. */
  height: 100px;
  width: auto;
  flex: none;
  transition: transform 160ms ease;
}

.brand-word {
  /* The wordmark has its own face. The site's grotesque is a workhorse chosen
     for tables and chrome; a name is the one place worth spending a typeface
     on, and this one is set nowhere else. */
  font-family: var(--wordmark);
  font-weight: 600;
  font-size: 2rem;
  letter-spacing: -0.02em;
  line-height: 1;
}

.brand-tld { color: var(--foot-accent); }

.brand-lockup:hover .brand-mark { transform: translateY(-2px); }
.brand-lockup:hover .brand-word { text-decoration: underline; text-underline-offset: 4px; }

.brand-line {
  color: var(--foot-muted);
  font-family: var(--prose);
  font-variation-settings: "opsz" 14;
  font-size: 1rem;
  line-height: 1.55;
  margin: 0;
  max-width: 34rem;
}

.brand-cta {
  font-family: var(--display);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--foot-accent);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
}

.brand-cta:hover { color: var(--foot-ink); }

.foot-col h2 {
  font-family: var(--display);
  font-size: 0.72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--foot-muted);
  margin: 0 0 0.9rem;
}

.foot-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.55rem; }
.foot-col a { color: var(--foot-ink); text-decoration: none; font-size: 0.95rem; }
.foot-col a:hover { text-decoration: underline; text-underline-offset: 3px; }

.foot-social a { display: inline-flex; align-items: center; gap: 0.55rem; }
.social-icon { width: 1.05em; height: 1.05em; flex: none; }
/* A handle is an address, not a word: it keeps its direction on a Hebrew page. */
.foot-social span { direction: ltr; unicode-bidi: isolate; }

/* The caveat and the colophon are both fine print, so they share the rule at
   the bottom rather than each holding a column. */
.foot-base {
  grid-column: 1 / -1;
  border-top: 1px solid var(--foot-rule);
  padding-top: 1.5rem;
  margin-top: 0.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 3rem;
  align-items: baseline;
  justify-content: space-between;
  color: var(--foot-muted);
}

.foot-caveat {
  font-family: var(--prose);
  font-variation-settings: "opsz" 12;
  font-size: 0.92rem;
  line-height: 1.55;
  margin: 0;
  max-width: 52ch;
}

.foot-colophon { font-size: 0.85rem; margin: 0; }

.pub-foot :focus-visible { outline-color: var(--foot-accent); }

@media (prefers-reduced-motion: reduce) {
  .brand-mark { transition: none; }
  .brand-lockup:hover .brand-mark { transform: none; }
}

/* The ground: the aurora as a field, and a grain over it.
 *
 * The wash is placed from the inline end, so it sits behind the empty quarter
 * of the footer in either direction rather than behind the brand block in one
 * of them.
 *
 * The grain is what keeps it from looking like every other soft gradient: a
 * fractal-noise filter at low opacity, blended so it roughens the light
 * without tinting it. It is coarse on purpose -- fine grain reads as a screen
 * artefact, this reads as something that was printed. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .pub-foot {
    --foot-ground: #0b1114;
    --foot-ink: #eef3f6;
    --foot-muted: #a7bac6;
    --foot-rule: rgba(238, 243, 246, 0.15);
    /* `--foot-accent` is not restated: it follows `--brand-accent`, which the
       root palette has already switched by the time this block applies. */
    --grain-ink: #ffffff;
    --grain-blend: overlay;
    --grain-opacity: 0.34;
    --wash-warm: rgba(252, 120, 56, 0.3);
    --wash-mid: rgba(195, 136, 139, 0.2);
    --wash-cool: rgba(61, 167, 189, 0.15);
  }
}

:root[data-theme="dark"] .pub-foot {
    --foot-ground: #0b1114;
    --foot-ink: #eef3f6;
    --foot-muted: #a7bac6;
    --foot-rule: rgba(238, 243, 246, 0.15);
    /* `--foot-accent` is not restated: it follows `--brand-accent`, which the
       root palette has already switched by the time this block applies. */
    --grain-ink: #ffffff;
    --grain-blend: overlay;
    --grain-opacity: 0.34;
    --wash-warm: rgba(252, 120, 56, 0.3);
    --wash-mid: rgba(195, 136, 139, 0.2);
    --wash-cool: rgba(61, 167, 189, 0.15);
}

.pub-foot { --wash-x: 92%; }
[dir="rtl"] .pub-foot { --wash-x: 8%; }

.foot-wash,
.foot-grain {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.foot-wash {
  background: radial-gradient(
    120% 150% at var(--wash-x) 40%,
    var(--wash-warm) 0%,
    var(--wash-mid) 30%,
    var(--wash-cool) 55%,
    transparent 74%
  );
}

.foot-grain {
  width: 100%;
  height: 100%;
  opacity: var(--grain-opacity);
  mix-blend-mode: var(--grain-blend);
}

.foot-grain rect { fill: var(--grain-ink); }

@media (max-width: 1000px) {
  .pub-foot-inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 2.25rem 2rem; }
  .foot-brand { grid-column: 1 / -1; }
}

:focus-visible { outline: 2px solid var(--bloc-a); outline-offset: 2px; }

@media (max-width: 1000px) {
  .stream-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .card.lead { grid-column: span 2; grid-row: auto; }
}

/* Below 1000px the masthead runs out of room, and what gives way is the
   publisher's name rather than anything the reader came for.
 *
 * The measurements: English sets `site.name` at 333px and the nav and the
 * controls take 371 more, which left 19px spare at 834px before the publisher
 * arrived. The lockup is 99px and the mark alone is 15. Hebrew's title is less
 * than half as wide, so its masthead is a single row down to 480px -- and 99px
 * broke that too, at every width from 640 down.
 *
 * So the name goes and the mark stays. The row also tightens its gaps, from
 * 2rem to 1.25rem, which is the other half of the payment: with both, English
 * still holds its title on one line down to 827px, sixteen pixels off where it
 * did before the mark existed. With neither it wraps from 950 -- and this
 * stylesheet already says, twice, that a masthead on two lines reads as a
 * mistake.
 *
 * The name is hidden from the eye and not from the page: it is what gives this
 * link its accessible name, and an `aria-label` in its place would be the same
 * two words maintained twice. The phone keeps its own `gap` rule below. */
@media (max-width: 1000px) {
  .pub-head-inner { gap: 1.25rem; }

  .masthead-word {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
}

/* Below 900px the nav leaves the row and goes behind the three-line icon.
 *
 * This is what keeps the masthead to one line all the way down: the three
 * links were 200px the row could not spare, and every layout this stylesheet
 * used to buy with wrapping -- the English title on two lines from 826, the
 * stack at 640, the mark-led phone masthead at 480 -- existed to absorb them.
 * With the links in the menu, none of those layouts has a reason to exist,
 * and the masthead below 900px is the same one row it is above. */
@media (max-width: 900px) {
  .pub-nav { display: none; }
  .nav-menu { display: block; }
}

@media (max-width: 640px) {
  /* The full English title is 333px at 1.02rem, which no narrow row can hold
     beside three controls and the publisher's mark. `short_name` takes over
     here -- a real short title, not a truncation -- and steps down to
     0.86rem. Hebrew's short title is a quarter of the row and needs neither,
     but a single rule beats a language-conditional one. */
  .wordmark { font-size: 0.86rem; }
  .wordmark-full { display: none; }
  .wordmark-short { display: inline; }
  /* One row is the point, so the gaps stop paying for wrapped layouts and
     start paying for the row: tighter between the groups, tighter inside the
     controls. */
  .pub-head-inner { gap: 0.75rem; }
  .pub-controls { gap: 0.45rem; }
  main, .pub-head-inner, .pub-foot-inner { width: min(100%, 100% - 2rem); }
  .pub-foot-inner { grid-template-columns: minmax(0, 1fr); }
  .brand-mark { height: 72px; }
  .brand-word { font-size: 1.75rem; }
  .stream-grid { grid-template-columns: minmax(0, 1fr); }
  .card.lead { grid-column: auto; }
  .hero { padding: 2.5rem 0 2rem; }
}

/* The phone. Measured at 320px English: the short title (194px), two pill
 * controls, the menu and the publisher's mark come to 389px against a 288px
 * content box, and no font a title can survive closes a 100px gap. So the
 * phone pays three ways: `compact_name` -- 'Forecast 2026', the same title
 * Hebrew has carried at every width -- the controls give up padding they
 * were holding for a mouse, and the publisher's mark leaves the row. The
 * mark is attribution, and the footer still carries the full lockup; a
 * masthead on one line is worth more to a phone reader than a 15px repeat
 * of what the footer says in full. */
@media (max-width: 480px) {
  .wordmark-short { display: none; }
  .wordmark-compact { display: inline; }
  .masthead-brand { display: none; }
  .lang-switch a { padding-inline: 0.5rem; }
  .pub-controls .theme-toggle,
  .nav-menu summary { padding-inline: 0.45rem; }
  .pub-head-inner { gap: 0.6rem; }
  .pub-controls { gap: 0.35rem; }
}

/* The strip needs room to be a shape rather than a smear, and a little air
   under it so a spike against the left edge does not touch the row rule. */
/* The strip needs vertical room; its header does not. Applying the padding to
   the column rather than the cell pushed "Distribution" below the baseline
   every other heading in the row sits on. */
/* The mark and the name, side by side, however many lines the name takes.
   They were two inline things in one cell, and a cell narrow enough -- between
   about 900 and 1100 pixels, where the caption rail is still beside the plate
   -- broke the line between them and left the mark stranded above its name. */
.lists-table .list-name { display: flex; align-items: center; }

/* 26% rather than the 32% it was: the list column now opens with the list's
   mark, and the width for it comes from the widest column on the row rather
   than from the names, which were already wrapping to three lines. The strip
   is a shape, not a reading, and it loses nothing at this width. */
.strip-col { width: 26%; min-width: 9rem; }
td.strip-col { padding-block: 0.35rem; }
.strip-col .strip { height: 30px; }

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

/* A meta line mixes Hebrew words with Latin dates and numerals. Without an
   isolate, the bidi algorithm reorders the run and "21 Aug 2026 · 1 min read"
   arrives as "1 21". Each figure is isolated rather than the line, so the
   Hebrew around them still reads right to left. */
[dir="rtl"] .meta,
[dir="rtl"] .hero-meta,
[dir="rtl"] .bloc-figures em,
[dir="rtl"] .provenance .run-id { unicode-bidi: isolate; }

[dir="rtl"] .cta,
[dir="rtl"] .article-back a { direction: rtl; }

/* ---- what the forecast is made of -------------------------------------- */

.provenance { display: grid; gap: 2rem; }

.prov-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1.25rem 2rem;
  margin: 0;
}

.prov-figures > div { min-width: 0; }
.prov-figures dt {
  font-family: var(--display);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.prov-figures dd {
  margin: 0.2rem 0 0;
  font-family: var(--display);
  font-variation-settings: "wdth" 108;
  font-weight: 700;
  font-size: 1.9rem;
  line-height: 1;
  /* Tabular, so the four figures sit on a common grid, but start-aligned:
     `.num` ends numbers at the far edge of their cell, which is right for a
     table column and wrong under a label that begins at the other one. */
  font-variant-numeric: tabular-nums;
}
.prov-note { margin: 0.3rem 0 0; font-size: 0.78rem; color: var(--muted); }

/* One bar per poll, oldest at the start, each as tall as the weight it
   carried. The shape is the argument: everything before the last fortnight is
   a stub, which is what a ten-day half-life looks like when you draw it. */
.prov-recency { margin: 0; }
.prov-track {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 76px;
  /* Pinned, like every other seat-and-time axis on the page: the chamber does
     not mirror, so neither does the campaign it was polled over. */
  direction: ltr;
}
.prov-mark {
  flex: 1 1 0;
  min-width: 2px;
  /* A floor, so a poll that counted for a fortieth is still visibly present
     rather than absent -- it is in the run, and the section is about what the
     run read. */
  height: calc(6% + 94% * var(--prominence));
  background: var(--bloc-a);
  opacity: calc(0.28 + 0.72 * var(--prominence));
  border-radius: 2px 2px 0 0;
}

.prov-recency figcaption {
  display: flex;
  justify-content: space-between;
  margin-top: 0.5rem;
  font-family: var(--mono-label);
  font-size: 0.72rem;
  color: var(--muted);
  direction: ltr;
}
[dir="rtl"] .prov-recency figcaption { flex-direction: row; }

.prov-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 1.75rem 2.5rem; }
.prov-column { min-width: 0; }
.prov-column h3,
.prov-sensitivity h3 {
  font-family: var(--display);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  margin: 0 0 0.75rem;
}
.prov-column ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.45rem; }
.prov-column li {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(3rem, 5rem) 2.5rem;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.88rem;
}
.prov-who { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prov-bar { display: block; height: 8px; background: var(--surface-sunken); border-radius: 999px; }
.prov-bar i { display: block; height: 100%; background: var(--bloc-a); border-radius: 999px; }
.prov-share { text-align: end; color: var(--muted); font-size: 0.8rem; }

/* Leave-one-out. A rule above it, because it answers a different question
   from the two weight columns it follows: those say how much of the evidence
   a pollster is, this says how much of the answer. */
.prov-sensitivity {
  border-block-start: 1px solid var(--rule);
  padding-block-start: 1.75rem;
  /* A grid item's automatic minimum is its min-content width, so without this
     the table inside sets the track and a phone gets a page that scrolls
     sideways. `.prov-column` beside it carries the same declaration for the
     same reason -- the `.scroll` wrapper can only clamp a table if something
     has clamped the wrapper. */
  min-inline-size: 0;
}
.prov-sensitivity p {
  margin-block: 0.75rem 0;
  /* Capped, so the paragraph does not run the full width of a breakout plate,
     and pinned to the inline start in the same breath. A cap with no stated
     inline margin is half a measure: it says how long the box is and leaves
     where it sits to whichever edge the container starts at. Start is what
     body prose wants -- the left in English, the right in Hebrew -- but it is
     a decision, and an unwritten `0` inside a shorthand does not read as one. */
  margin-inline: 0;
  max-inline-size: 60ch;
  font-size: 0.88rem;
}

/* The table is its own object, not a continuation of the sentence above it.
   The caption sits tight under the prose otherwise, and reads as a fourth
   line of it. */
.prov-sensitivity .scroll { margin-block-start: 1.6rem; }

/* The column heads take `.num`, the same class as the figures under them, and
 * that is the whole of the rule: `text-align: end` resolves against the
 * *element's own* direction, and `.num` pins `direction: ltr` on a Hebrew
 * page. A head that took only the alignment resolved `end` to the left while
 * its figures resolved it to the right, so every Hebrew column head sat a
 * column-width away from the numbers it named. English was correct, because
 * there both directions agree -- which is exactly how it shipped.
 *
 * The reason the head was given its own class was a fear that pinning LTR
 * would reorder a multi-word Hebrew label. It does not: the pin isolates, and
 * a run of Hebrew words is one strong-RTL run that the bidi algorithm orders
 * correctly inside it. `קולות שלא בחרו איש` heads the threshold table under
 * this same class and has always been right. The label that must *not* be
 * pinned is a number inside a sentence, and that is what `.num-prose` is for.
 */

/* A column head is a label even when its column is figures.
 *
 * #56 split the mono role and made `font-variant-numeric: tabular-nums` the
 * discriminator: a rule whose glyphs line up in a column takes `--mono`,
 * everything else takes `--mono-label`. That is right for a cell and it
 * over-keeps for a head, because a head inherits its cell's class -- which is
 * the whole point, it is how the two stay aligned -- and takes Plex Mono's
 * space along with the alignment. A head holds words and no digits, so
 * nothing in it has to line up with anything.
 *
 * Measured in Chrome on the rendered Hebrew page at 13.6px: the space between
 * two Hebrew words in these heads was 8.17px, against 2.26px in the threshold
 * table's heads, which reach Archivo by another route and were always right.
 *
 * `font-variant-numeric` goes back to `normal` in the same rule rather than
 * being left to inherit, because `--mono-label` beside `tabular-nums` is the
 * contradiction `test_no_rule_takes_the_label_role_and_tabular_figures` exists
 * to catch, and a rule should not need the cascade resolved to be read. */
[lang="he"] .sens-table thead th,
[lang="he"] .lists-table thead th.num-prose {
  font-family: var(--mono-label);
  font-variant-numeric: normal;
}

.sens-table caption {
  text-align: start;
  /* A label, not a column: nothing here lines up under anything, and it holds
     two Hebrew words, so it takes the label half of the mono role. In `--mono`
     the letters would come from Assistant and the space from Plex Mono, at
     more than twice the width. */
  font-family: var(--mono-label);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  padding-block-end: 0.6rem;
}

@media (max-width: 640px) {
  .prov-figures dd { font-size: 1.5rem; }
  .prov-track { height: 60px; }

  /* Five columns do not fit in 390px, and `.scroll` gives up its sideways
     scroll at this width -- the site settled once that a page which scrolls
     down must not also scroll across, and a disclosure is not the place to
     reopen it. So the row stops being a row: the pollster takes a line with
     its poll count beside it, and the three blocs take the next, one track
     each. The header goes, because every cell now carries its own label. */
  .sens-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .sens-table tr {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: baseline;
    gap: 0.5rem 0.9rem;
    padding-block: 0.8rem;
    border-block-end: 1px solid var(--rule);
  }
  .sens-table td { border: 0; padding: 0; }
  .sens-table td:first-child { grid-column: 1 / 3; grid-row: 1; font-weight: 600; }
  .sens-table td:nth-child(2) { grid-column: 3; grid-row: 1; }
  .sens-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 has no capitals to letter-space, so the travelling labels drop the
   treatment the same way every other label in the mono and display roles
   does. */
[lang="he"] .sens-table td[data-label]::before { text-transform: none; letter-spacing: 0; }

/* The hero headline is a link, and should not look like one until it is
   reached for -- it is already the biggest thing on the page. */
.hero h1 a { color: inherit; text-decoration: none; }
.hero h1 a:hover { text-decoration: underline; text-underline-offset: 6px; }

/* ---- the lists table, on a phone ---------------------------------------
 *
 * Five columns do not fit in 390px. The table sits in a scroll container so
 * nothing was clipped, but the histogram -- the column the table exists for --
 * ended up past the right edge, reachable only by scrolling sideways in a
 * page that scrolls down. A reader would never know it was there.
 *
 * So below this width the row stops being a row: the name and its two figures
 * take one line, and the distribution takes the next at full width, which is
 * more room than it ever had in a column. Nothing is dropped and nothing needs
 * scrolling. The header row goes, because each cell now carries its own label.
 */
@media (max-width: 640px) {
  .scroll { overflow-x: visible; }
  .lists-table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
  .lists-table tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: baseline;
    gap: 0.15rem 0.9rem;
    padding: 0.7rem 0;
    border-bottom: 1px solid var(--rule);
  }
  .lists-table td { border: 0; padding: 0; }
  .lists-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);
  }
  /* The name leads, with the seat count and how often the list wins anything
     beside it -- the two figures a reader scanning the column wants. */
  .lists-table td:first-child { grid-column: 1; grid-row: 1; align-self: center; }
  .lists-table td[data-kind="seats"] { grid-column: 2; grid-row: 1; }
  .lists-table td[data-kind="frequency"] { grid-column: 3; grid-row: 1; }
  /* The distribution spans the whole second line, with the conditional range
     beside it -- the two belong together: one is the shape, the other is where
     it lands when the list is in. */
  .lists-table td.strip-col { grid-column: 1 / span 2; grid-row: 2; width: auto; min-width: 0; }
  .lists-table td.strip-col .strip { height: 34px; }
  .lists-table td[data-kind="range"] { grid-column: 3; grid-row: 2; align-self: end; }
}


/* ---- the section rail -------------------------------------------------- */

/* An index of the page that stays beside it, and the offset everything else
 * that stays put is measured from.
 *
 * The masthead is `position: sticky` and opaque enough to hide what slides
 * under it, so a second sticky thing at `top: 0` is a second sticky thing
 * nobody can read. `--head-h` is what the masthead actually measures;
 * `section-nav.js` overwrites it with the observed height, and the values
 * here are what the four header layouts settle at, so the page is right
 * before the script runs and right without it.
 *
 * Four now. The masthead has one unwrapped row, then a row whose title has
 * wrapped inside it, then a stack, then the phone -- where the mark leads the
 * masthead instead of sitting in a row, and the stack's number no longer
 * covers it. For a long time only the first and the third had a value here,
 * so on an English page 641 to 826px wide with no script this was 20px short
 * of what the masthead measured, and a link to a section landed with the
 * section's top rule 9px under it. iPad portrait is 768. It survived because
 * the band is narrow, one language wide, and gone the moment JavaScript
 * runs.
 *
 * Each value is the tall end of its band, measured in a browser at both
 * languages. Over-guessing costs a little air above a heading, which is why
 * Hebrew's short masthead is allowed to share English's number.
 *
 * `--nav-h` is the chip the rail collapses into below 1240px, and is zero
 * where there is no chip. `--sticky-top` is the two added: the line under
 * which the page is actually visible.
 */
:root {
  /* One row, title unwrapped -- and the only band where the masthead is no
     longer one height. Every item in it is a clamp between 1000px and 1800px,
     so this band is a ramp: 57.6px at 1001 in English, 71.3 at 1440, and
     82.5 from 1800 up, where every clamp has reached its ceiling and the
     masthead stops growing. Hebrew is 1.9px taller throughout, because its
     glyphs make the language pill's line box taller, so the number to cover
     is Hebrew's 84.48 at 1800 and 5.3rem is the first sixteenth over it.

     A single value over a ramp means up to 25px of air above a heading at
     the narrow end of the band, for a reader with no script. That is the
     cheap failure and this file has taken it before by a wider margin: the
     band below covers a one-row masthead of its own. The value that would
     be wrong is a short one. */
  --head-h: 5.3rem;
  --nav-h: 0rem;
  --sticky-top: calc(var(--head-h) + var(--nav-h));
  --sticky-pad: 0.7rem;
  --section-nav-w: 11rem;
  --section-nav-gap: 2.5rem;
  --gutter: 1.5rem;
}

@media (max-width: 900px) {
  /* One row, all the way down. The nav is behind the menu icon from here, so
     the layouts this used to be three bands for -- the wrapped English title,
     the stack, the mark-led phone masthead -- no longer exist. Every clamp is
     at its floor below 1000px, so the whole range draws the one-row height:
     57.6px in English, 59.4 in Hebrew, and 3.85rem is a sixteenth over the
     taller. Re-measured after the menu landed, both languages, 320 to 900. */
  :root { --head-h: 3.85rem; }
}

@media (max-width: 640px) {
  /* The page keeps a narrower edge from here; the masthead no longer changes
     shape at this width, only the gutter does. */
  :root { --gutter: 1rem; }
}

html { scroll-behavior: smooth; }

/* Without this an anchor lands under the masthead, which is the failure the
   offset exists to stop -- reached by a link rather than by scrolling. It is
   also the number the rail's mark is read back from, so the section the rail
   points at is the section the link lands on. */
.article-body > .plate { scroll-margin-block-start: calc(var(--sticky-top) + var(--sticky-pad)); }

/* ---- skip link --------------------------------------------------------- */

.skip-link {
  position: fixed;
  inset-block-start: 0.6rem;
  inset-inline-start: 0.6rem;
  z-index: 40;
  transform: translateY(-250%);
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--rule);
  border-radius: 999px;
  padding: 0.45rem 1rem;
  font-family: var(--mono-label);
  font-size: 0.74rem;
  text-decoration: none;
}

.skip-link:focus { transform: none; }

/* ---- the rail itself --------------------------------------------------- */

/* A hairline with a mark on it, which is how every other division on this
 * page is drawn. The alternative -- a boxed menu with a fill behind the
 * current row -- would be the only card on a site that has none.
 *
 * A grid column rather than a float or a fixed overlay, because the rail has
 * to be something the figures are laid out around: at 1420px there is no
 * margin to hang it in, and one that overlapped would sit on the chamber. The
 * figures give up `--section-nav-w` plus the gap for it.
 *
 * The whole rail is one `<details>`, open as it is served. Wide, it reads as
 * a rail with a label; narrow, the script shuts it into a chip under the
 * masthead. With no script it stays open and is a plain list of anchors,
 * which is the entire navigation -- only the mark showing where the reader
 * is needs JavaScript.
 */
.article.wide { display: grid; grid-template-columns: minmax(0, 1fr); }

.section-nav { margin-bottom: 2.5rem; }

.section-nav summary {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  cursor: pointer;
  list-style: none;
  font-family: var(--display);
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
  padding-block: 0.4rem;
}

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

.section-nav-here {
  min-width: 0;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.section-nav-here:not(:empty)::before {
  content: "";
  display: inline-block;
  width: 1px;
  height: 0.8em;
  margin-inline-end: 0.5rem;
  background: var(--rule);
  vertical-align: -0.05em;
}

.section-nav-list {
  list-style: none;
  margin: 0.35rem 0 0;
  padding: 0;
  border-inline-start: 1px solid var(--rule);
}

.section-nav-list a {
  display: block;
  padding-block: 0.42rem;
  padding-inline: 0.85rem 0;
  margin-inline-start: -1px;
  border-inline-start: 2px solid transparent;
  font-family: var(--display);
  font-size: 0.79rem;
  line-height: 1.35;
  color: var(--muted);
  text-decoration: none;
}

.section-nav-list a:hover { color: var(--ink); }

/* The one mark on the rail. `aria-current` is what the script sets, so what a
   reader sees and what a screen reader is told are one attribute rather than
   a class and an attribute that can come to disagree. */
.section-nav-list a[aria-current="true"] {
  color: var(--ink);
  font-weight: 600;
  border-inline-start-color: var(--bloc-a);
}

[lang="he"] .section-nav summary { text-transform: none; letter-spacing: 0; font-size: 0.8rem; }
[lang="he"] .section-nav-list a { font-size: 0.88rem; }

/* ---- the rail beside the page ------------------------------------------ */

@media (min-width: 1240px) {
  .article.wide {
    grid-template-columns: var(--section-nav-w) minmax(0, 1fr);
    column-gap: var(--section-nav-gap);
  }
  /* The headline and the standfirst keep the full measure: the rail is a
     margin down the sections, not a column the headline is set against. */
  .article.wide > .article-head { grid-column: 1 / -1; }

  .section-nav {
    position: sticky;
    top: calc(var(--sticky-top) + var(--sticky-pad));
    align-self: start;
    /* `dvh` and not `vh`: on iOS the toolbars are inside `vh`, so a rail sized
       against it is cut off by chrome drawn over it. */
    max-height: calc(100dvh - var(--sticky-top) - 4rem);
    overflow-y: auto;
    margin-bottom: 0;
  }

  /* Redundant beside the mark on the list itself. */
  .section-nav-here { display: none; }
}

/* ---- the rail as a chip ------------------------------------------------- */

/* Below the width that fits a column, the rail becomes what it should be on a
 * phone: a line under the masthead naming the section the reader is in, that
 * opens into the list.
 *
 * A drawer or a full-screen overlay was the other answer and is the wrong one
 * here. Both need a script to open at all, both need a focus trap and a
 * scroll lock to be correct, and both spend the whole screen answering "where
 * am I" by hiding the page the reader is trying to place themselves in. Shut,
 * this control is already the answer; open, it is the same list as the rail.
 *
 * Sticky only once the script has run. Served as it is -- open, in flow -- a
 * sticky panel would pin two thirds of a phone screen over the article and
 * never let go.
 */
@media (max-width: 1239.98px) {
  [data-section-nav="ready"] { --nav-h: 2.9rem; }

  [data-section-nav="ready"] .section-nav {
    position: sticky;
    top: var(--head-h);
    z-index: 15;
    margin-bottom: 2rem;
    background: color-mix(in oklab, var(--ground) 92%, transparent);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--rule);
    /* Full bleed, so the line under it reads as chrome rather than as
       something inside the article. */
    margin-inline: calc(-1 * var(--gutter));
    padding-inline: var(--gutter);
  }

  [data-section-nav="ready"] .section-nav summary {
    block-size: var(--nav-h);
    padding-block: 0;
  }

  /* The list is the panel now, so it is bounded and scrolls inside itself
     rather than running past the bottom of the screen. */
  [data-section-nav="ready"] .section-nav-list {
    max-height: min(56dvh, 22rem);
    overflow-y: auto;
    margin-block: 0 0.5rem;
    /* A notched phone puts the home indicator over the last row. */
    padding-block-end: env(safe-area-inset-bottom);
  }
}

/* Nothing here animates under the query, the jump included. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ---- the heading stays with its section -------------------------------- */

/* The rail beside a plate was pinned at `top: 1.5rem`, which is behind the
 * masthead: its paragraphs stayed put and its `<h2>` sat under 58px of
 * blurred chrome, so a reader deep in a section could not see which one they
 * were in.
 *
 * Two changes, and both are needed. The rail is pinned below the masthead
 * rather than under it. And the heading is pinned inside the rail as well,
 * because a rail as tall as its own section has no room left to stick --
 * the chamber's is 640px in a 677px section -- and takes the heading down
 * with it. The heading carries the page's ground so the prose passing under
 * it is not read through it.
 *
 * Only where the rail is a column. Below 900px the plate stacks and the chip
 * above is already naming the section, and two answers to one question is
 * one too many.
 */
@media (min-width: 901px) {
  .plate > .rail { top: calc(var(--sticky-top) + var(--sticky-pad)); }

  .plate .rail h2 {
    position: sticky;
    top: var(--sticky-top);
    z-index: 5;
    background: var(--ground);
    /* The gap under the heading is padding and not margin on purpose: a
       margin is transparent, so the first line of the prose passing under a
       pinned heading showed through it, sliced in half. */
    padding-block: var(--sticky-pad) 0.75rem;
    margin: calc(-1 * var(--sticky-pad)) 0 0;
  }
}


/* ---- the countdown ----------------------------------------------------- */

/* The one purely decorative thing on the page, so it is built out of what the
   rest of the page is already built out of: hairline rules, the display face
   at the size a seat count is set in, mono labels, and the bloc teal. A filled
   panel in a colour of its own would be an object imported from somewhere
   else, sitting under a headline that is not.
 *
 * It carries the whole of what the site now says about time to polling day.
 * The meta line above it says when the forecast was made and stops there.
 *
 * IT LIVES IN THE OPENING, UNDER THE SEAT ARC, and on both pages -- the front
 * page and the forecast page draw one opening from one macro, so the counter
 * is in it once and appears on each. It was a band across the forecast page's
 * article head until then, separated the way a newspaper separates a standing
 * element: a heavy rule above, a hairline below, and the whole thing capped to
 * `--column` so its length was the prose measure rather than the window. All
 * of that is gone, and none of it is kept as an override -- the panel has one
 * home now, and a band's rules left behind to be overridden is the second copy
 * that drifts.
 *
 * The arc's box is where it goes because the arc's box has the room: the dome
 * ends at its chord and the hero's other column runs taller than it does, so
 * the clock sits in air the page had already paid for. It reads as one
 * instrument with the arc, which is the other decorative thing on the picture.
 * Nested *inside* the dome was tried first and the hollow is narrower than the
 * clock at that height -- the digits landed on the last two rows of seats.
 *
 * TWO THINGS HERE NAME A PHYSICAL SIDE, AND BOTH ARE THE POINT. The clock is
 * pinned `direction: ltr`, and so is the campaign gauge. A duration is a
 * measurement, not a sentence: Hebrew writes a clock time as 12:34 and never
 * 34:12, and days/hours/minutes/seconds is the same composite, ordered by
 * magnitude rather than by reading. Left to the writing direction the four
 * boxes mirrored, and a Hebrew reader was handed seconds where the days
 * belong. `_trend.html` makes this call for the plot area and
 * `.masthead-brand` for the lockup; the clock is the third case, and the one
 * that had it wrong. The gauge is pinned with it because two measures of the
 * same span draining in opposite directions inside one panel is worse than
 * either direction on its own.
 *
 * Only the order of the boxes is pinned, and nothing else in here is given a
 * direction of its own. The unit word is one Hebrew run inside an LTR
 * paragraph and bidi reorders it correctly with no help; the panel around the
 * clock -- the head, the campaign line, the summary -- takes the page's
 * direction. Each figure is its own box, so no digit run can merge across a
 * separator. */

.countdown {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-block-start: 0.6rem;

  /* The figure ramp, as four tokens rather than four colours, because the
     panel does not always stand on the same ground -- see the note on the
     ramp below and the redefinition in the stacked band. */
  --figure-days: #ffffff;
  --figure-hours: #9aacb8;
  --figure-minutes: #8698a5;
  --figure-seconds: #748895;
}

/* The clock above the line that names it, which is the other way round from
   the order the markup is in. The markup leads with the head because that is
   the reading order the panel's own sentence wants -- what this is, then the
   figures -- and `order` moves the boxes without moving the document, so
   assistive technology still meets them in that order. It is only ever static
   text being arranged; nothing here takes focus. */
.countdown-clock { order: 1; }
.countdown-head { order: 2; }
.countdown-run { order: 3; }
.countdown-since { order: 4; }
.countdown-said { order: 5; }

.countdown-head {
  display: flex;
  justify-content: center;
  align-items: baseline;
  gap: 0.7rem;
  margin: 0.3rem 0 0;
  font-family: var(--mono-label);
  font-size: 0.66rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}
.countdown-date { color: var(--muted); }

/* Two labels are in the markup and one is shown, for the same reason the two
   closing lines are: the script changes state and cannot write prose. "To
   polling day" standing over "Polling stations are open" would be a
   contradiction left behind by a state change. */
.countdown-label { display: none; color: var(--bloc-a); }
.countdown[data-countdown-state="counting"] .countdown-label[data-label="counting"] { display: inline; }
.countdown:not([data-countdown-state="counting"]) .countdown-label[data-label="today"] { display: inline; }

/* Served, the panel shows the days figure alone: the finer segments are in
   the markup and are revealed only once `countdown.js` has put a live value
   in them. A minutes figure rendered into a file behind a CDN is a wrong
   number rather than a coarse one. */
.countdown-clock {
  display: none;
  justify-content: center;
  /* The pin. Four boxes in magnitude order, the same order in both
     languages; see the note at the head of this section. */
  direction: ltr;
}
.countdown[data-countdown-state="counting"] .countdown-clock { display: flex; }

.countdown-seg {
  display: none;
  flex-direction: column;
  gap: 0.3rem;
  padding-inline: clamp(0.5rem, 1.4vw, 0.8rem);
  border-inline-start: 1px solid var(--rule);
}
/* The separator only. The first box keeps its leading padding, because the
   padding is what centres the clock: the group's box is centred, so the ink
   inside it is centred only while the two end boxes are inset by the same
   amount. Stripped from the first box -- which it was, from when the clock
   was left-aligned in a 34rem panel and the days digit had to sit flush with
   the start edge -- the digits sat half a padding left of centre, 9.2px at
   1500px, under a campaign line that is centred exactly. Symmetric padding
   also holds for every count of visible boxes: four live, three under reduced
   motion, one as served. */
.countdown-seg:first-child { border-inline-start: none; }
.countdown-seg[data-unit="days"] { display: flex; }
.countdown[data-countdown-live] .countdown-seg { display: flex; }

.countdown-seg b {
  font-family: var(--display);
  font-variation-settings: "wdth" 118;
  font-weight: 700;
  font-size: clamp(1.5rem, 0.9rem + 1.5vw, 2.1rem);
  line-height: 0.92;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}

/* THE BREAK IS AFTER THE DAYS, not spread evenly across the four.
 *
 * At two months out the days figure is the one a reader acts on and repeats;
 * hours, minutes and seconds are one clock reading, and they are there because
 * a clock ticks. Set at one weight the four read as a single long number and
 * the eye has nowhere to land -- which is the whole complaint against a row of
 * equal figures.
 *
 * So: days at full ink, and the other three a tight group tapering only gently
 * among themselves. An even four-step ramp was tried and is worse in both
 * directions at once -- no neighbouring pair is far enough apart to tell apart,
 * and nothing in it says which figure matters.
 *
 * The steps are literal rather than `--muted` and a tint of it, because they
 * are read against the picture's scrim in both palettes: the opening redefines
 * its own tokens over the painting, and a ramp derived from a page token would
 * be derived from a value this subtree has already replaced.
 *
 * AND NOT THE BLOC HUES. Teal, amber and violet mean the three blocs
 * everywhere on this page, and the arc immediately above this clock is drawn
 * in exactly those three. Painting the units with them would give one palette
 * two meanings inside one instrument. */
.countdown-seg[data-unit="days"] b { color: var(--figure-days); }
.countdown-seg[data-unit="hours"] b { color: var(--figure-hours); }
.countdown-seg[data-unit="minutes"] b { color: var(--figure-minutes); }
.countdown-seg[data-unit="seconds"] b { color: var(--figure-seconds); }

/* AND THE GROUND IS NOT ALWAYS THE PICTURE, which is what makes the ramp four
 * tokens rather than four colours.
 *
 * Held wide the whole opening lies on the painting and the scrim under it, so
 * the steps above are read against something dark whatever the reader's theme
 * is. Stacked, the arc gets a row of its own *below* the picture -- on the
 * page's own ground, in the page's own palette, deliberately, because the
 * arc's shading reads `--shade-toward` and would shade toward black on black
 * otherwise. The counter shares that row. In the light theme it therefore
 * stands on #eef1f3, where a white days figure is invisible and the three
 * greys under it are the only legible things in the panel: the ramp inverts,
 * and the one figure a reader acts on is the one that disappears.
 *
 * So on that row the steps are taken from the palette in force. `--ink` and
 * `--muted` already give the large break; the mixes give the gentle taper
 * under it, and both follow the theme because the tokens do. */
@media (max-width: 1160px), (max-height: 869px) {
  .poster .hero-chamber .countdown {
    --figure-days: var(--ink);
    --figure-hours: color-mix(in oklab, var(--muted) 88%, var(--ink));
    --figure-minutes: var(--muted);
    --figure-seconds: color-mix(in oklab, var(--muted) 84%, var(--ground));
  }
}

/* The box order is pinned; the word inside it is given nothing at all, and
   that is the whole of what it needs. `ימים` is one strong-RTL run inside an
   LTR paragraph, so bidi reorders it correctly on its own.
   `unicode-bidi: plaintext` was tried here as future-proofing for a label
   that grew past one word. It is not free: `plaintext` sets the *paragraph*
   base direction, which is also what `text-align: start` resolves against,
   and the label is a blockified flex item stretched to the segment's width.
   So the Hebrew word was flushed to the segment's trailing edge while the
   digits filled from its leading edge -- `DAYS` under the left of `65` and
   `ימים` under the right of it, in the same clock. If a label ever does grow
   into a phrase, that is the commit to decide it in. */
.countdown-unit {
  font-family: var(--mono);
  font-size: 0.62rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--muted);
}

/* A digit repainting once a second, for as long as the tab is open, is
   content moving on its own. The reader who asked for less of that keeps the
   minutes -- the granularity anything is decided at -- and loses the segment
   nobody acts on. `countdown.js` reads the same preference and steps to the
   minute, so the hidden segment is not being updated behind the rule. */
@media (prefers-reduced-motion: reduce) {
  .countdown[data-countdown-live] .countdown-seg[data-unit="seconds"] { display: none; }
}

/* The two ends. One line each, and unlike the clock they are not hidden from
   assistive technology: in these states the visible line is the whole message. */
.countdown-said {
  display: none;
  margin: 0;
  text-align: center;
  font-family: var(--display);
  font-variation-settings: "wdth" 112;
  font-weight: 700;
  font-size: clamp(1.35rem, 1rem + 1.5vw, 1.9rem);
  line-height: 1.15;
}
.countdown[data-countdown-state="open"] .countdown-said[data-said="open"] {
  display: block;
  color: var(--bloc-a);
}
.countdown[data-countdown-state="closed"] .countdown-said[data-said="closed"] {
  display: block;
  color: var(--muted);
}

/* The campaign, drawn as the measure it is: dissolution at one end, polling
   day at the other, both read from the election record rather than assumed.
   It is the same span the trend chart marks with its dissolution line, and it
   is what stops the clock being four numbers with nothing behind them. The
   fill is a block child, so it grows from the inline start of its track; a
   gradient or an offset would have had to name a side.

   The track is pinned to run the clock's way rather than the page's. Left to
   the writing direction the fill grew rightwards in English and leftwards in
   Hebrew, which put two measures of the same campaign running opposite ways
   inside one panel. It is the same argument as the clock's: elapsed time is a
   quantity on an axis, and the axis does not turn over with the prose. */
.countdown-run {
  display: block;
  direction: ltr;
  /* The gauge is the panel's base rather than a rule under a column, so it is
     given a length of its own; stretched to the arc's full width it read as a
     divider between the picture and the page instead of as a measure. */
  inline-size: 58%;
  block-size: 2px;
  margin-block-start: 0.45rem;
  background: var(--rule);
}
.countdown-run-done {
  display: block;
  block-size: 100%;
  background: var(--bloc-a);
}
/* Kept, small, rather than dropped for room: an unlabelled bar under a clock
   is a mark a reader cannot read, which is the defect `#70` was opened to fix
   elsewhere on this page. */
.countdown-since {
  margin: 0.4rem 0 0;
  text-align: center;
  font-family: var(--mono-label);
  font-size: 0.64rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}

/* The sentence assistive technology is given in place of the clock. Off
   screen, in no live region, and static -- so a screen reader reads one
   correct thing about polling day instead of four numbers every second. */
.countdown-summary {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
}

/* Hebrew has no capitals to letter-space and reads smaller at the same
   nominal size, which is the treatment `tokens.css` already gives every other
   label set in the mono role. */
[lang="he"] .countdown-head,
[lang="he"] .countdown-unit,
[lang="he"] .countdown-since {
  text-transform: none;
  letter-spacing: 0;
}
[lang="he"] .countdown-unit { font-size: 0.74rem; }
[lang="he"] .countdown-since { font-size: 0.76rem; }

/* Latin digits inside a Hebrew line, the same reason `.meta` needs it. */
[dir="rtl"] .countdown-head,
[dir="rtl"] .countdown-since { unicode-bidi: isolate; }

/* ---- the method page ---------------------------------------------------- */

/* The five stages, drawn as a numbered band on a rule.
 *
 * The rule is one line across the whole list, and the badges sit on it with
 * the page's own ground behind them so it reads as cut rather than crossed.
 * That is deliberate rather than decorative: a line is symmetric, so it needs
 * no mirroring on a Hebrew page, where an arrow or a chevron would have to be
 * flipped and would be one more thing to get wrong in the language this site
 * is written in first. The numerals carry the direction instead, and they are
 * the list's own -- the markup is an `<ol>`, so the order is in the document
 * rather than in the paint.
 *
 * `-webkit-line-clamp` and friends are deliberately absent: a stage name that
 * outgrows its column wraps, and wrapping is the failure this can afford.
 */
.pipeline-figure { margin: 0; }

/* Named for a screen reader, drawn for nobody. The same clip the tables use
   when their heads stop being visible on a phone. */
.pipeline-caption {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.pipeline {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  gap: 0;
  list-style: none;
  margin-block: 2.5rem 3rem;
  margin-inline: 0;
  padding: 0;
  position: relative;
  isolation: isolate;
}

.pipeline::before {
  content: "";
  position: absolute;
  inset-inline: 6%;
  inset-block-start: 1.05rem;
  block-size: 1px;
  background: var(--rule);
  z-index: -1;
}

.pipeline a {
  display: grid;
  justify-items: center;
  gap: 0.6rem;
  padding-inline: 0.4rem;
  color: var(--muted);
  text-decoration: none;
  text-align: center;
}

.pipeline a:hover { color: var(--ink); }
.pipeline a:hover .pipeline-step { border-color: var(--bloc-a); color: var(--ink); }

/* The badge, and the reason it declares a background: it is what cuts the
   rule behind it. A transparent badge would sit on a line running through the
   numeral. */
.pipeline-step {
  inline-size: 2.1rem;
  block-size: 2.1rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule);
  border-radius: 50%;
  background: var(--ground);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 0.9rem;
  line-height: 1;
}

.pipeline span {
  font-size: 0.82rem;
  line-height: 1.35;
  text-wrap: balance;
}

/* Hebrew stage names are one or two words where the English is three or four,
   and the label is not in the mono role -- so this is the step-up `tokens.css`
   gives Hebrew text at the same nominal size, not a mono fix. */
[lang="he"] .pipeline span { font-size: 0.88rem; }

/* Under about 34rem five columns give each name less than one word's width,
   so the band stands up instead. The rule turns with it: `inset-inline` and
   `inset-block` swap roles, and it is still one symmetric line. */
@media (max-width: 34rem) {
  .pipeline {
    grid-auto-flow: row;
    grid-auto-columns: auto;
    gap: 1.1rem;
    justify-items: start;
  }

  .pipeline::before {
    inset-inline: auto;
    inset-inline-start: 1.05rem;
    inset-block: 6%;
    inline-size: 1px;
    block-size: auto;
  }

  .pipeline a {
    grid-auto-flow: column;
    justify-items: start;
    align-items: center;
    gap: 0.9rem;
    text-align: start;
    padding-inline: 0;
  }

  .pipeline span { text-wrap: initial; }
}

/* The standfirst under the lede: the page's own voice rather than the
   forecast's, so it is set as prose and not as a caption. */
.method-intro {
  color: var(--muted);
  margin-block-start: 0.9rem;
}

/* The second paragraph of every stage -- what it is for, as against what it
   is. Marked rather than merely spaced, because it is the half of the page a
   reader is here for and a wall of even paragraphs hides it. */
.method-why {
  border-inline-start: 2px solid var(--rule);
  padding-inline-start: 1rem;
  color: var(--muted);
}

.method-links {
  list-style: none;
  padding: 0;
  margin-block-start: 1rem;
  display: grid;
  gap: 0.55rem;
}
