:root {
  --paper: #f4f2ed;
  --ink: #17171a;
  --muted: #6b6760;
  --line: #ddd8cd;
  --hair: #e8e4db;
  --pine: #1e3a30;
  --card: #fffdfa;
  --veil: rgba(244, 242, 237, 0.94);
  --shade: rgba(23, 23, 26, 0.06);
  /* One colour per kind of event, the same in every chart. Chosen to stay
     apart from each other for the common forms of colour blindness, which
     rules out putting the vehicles and the fires on the same red. */
  --cat-vehicle: #36678c;
  --cat-person: #b07533;
  --cat-bus: #6a5a9c;
  --cat-fire: #bf4630;
  --cat-plane: #7d8b95;
  --cat-other: #9a938a;
}

:root[data-theme="dark"] {
  /* Not the light sheet inverted: paper goes grey and ink goes muddy that way.
     These are picked so the webcam picture, which is what the page is for,
     still looks like a photograph and not a lit window in a dark room. */
  --paper: #14161a;
  --ink: #e9eaec;
  --muted: #9aa0a8;
  --line: #2b2f36;
  --hair: #22262c;
  --pine: #9dd3ba;
  --card: #1b1e23;
  --veil: rgba(20, 22, 26, 0.94);
  --shade: rgba(255, 255, 255, 0.07);
  /* Lifted, not reused. The daylight colours are picked to sit on paper and
     go muddy against a dark card. */
  --cat-vehicle: #5e9ec9;
  --cat-person: #d9a35c;
  --cat-bus: #9b8ad2;
  --cat-fire: #e0705a;
  --cat-plane: #a3b1bc;
  --cat-other: #b4aca1;
}

:root { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 13px/1.5 ui-sans-serif, system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
}

/* Header */

.top {
  position: sticky;
  top: 0;
  z-index: 1000;
  background: var(--veil);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}

.top-inner, main {
  max-width: 1200px;
  margin: 0 auto;
  padding-left: 24px;
  padding-right: 24px;
}

/* One row, always. The bar is read once on arrival and is in the way for the
   rest of the visit, so it spends the width it has rather than the height it
   does not: a section jumped to from here has to arrive whole, and every pixel
   this takes is a pixel the section cannot have. */
.top-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 20px;
  min-height: 40px;
  padding-top: 2px;
  padding-bottom: 2px;
}

.top-inner .eyebrow { display: none; }
.top-inner .brand-hash {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
}
.top-inner .brand-hash canvas {
  display: block;
  height: 18px;
  width: auto;
  max-width: 100%;
  image-rendering: pixelated;
}

/* The menu sits on the title's own line, and everything else shrinks to let it
   fit there. A second row for six words costs thirty pixels of every section
   below, every time anyone scrolls. */
/* The title and the menu keep their full size; only the readings give ground.
   Forbidding the whole row to wrap instead broke the title across two lines
   and folded the menu in half, which cost more height than it saved. */
.top-inner .brand,
.top-inner .onpage { flex: 0 0 auto; white-space: nowrap; }
/* No automatic margin before the end of the row. Placed on the menu it ate
   every spare pixel of the first line, which is what pushed the readings onto
   a second one: flex hands the leftover space to the first auto margin it
   meets, and that margin was in the middle. */
/* A basis of nothing, not of its natural width. With wrapping on, a flex item
   that asks for its full width is moved to the next line rather than squeezed,
   so asking for none is what keeps the readings on the title's line. */
.top-inner .facts { flex: 1 1 0; min-width: 0; }
.top-inner .langs { margin-left: auto; }

main {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding-top: 24px;
  padding-bottom: 64px;
}

.eyebrow {
  margin: 0;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-size: 10px;
  color: var(--muted);
}

h1 {
  margin: 0;
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.02em;
}

/* One line of readings, cut short rather than stacked. Wrapping was the quiet
   way to lose height: three columns of a label, a figure and two notes folded
   into seven lines and took fifty pixels off every section on the page. A
   reading that will not fit is better trimmed than moved down, because the
   figure at the head of it is the part anyone reads. */
.facts {
  display: flex;
  flex-wrap: nowrap;
  align-items: baseline;
  margin: 0;
  min-width: 0;
  overflow: hidden;
}

.facts > div {
  display: flex;
  flex-wrap: nowrap;
  align-items: baseline;
  gap: 5px;
  padding: 0 10px;
  border-left: 1px solid var(--line);
  white-space: nowrap;
  /* Allowed to give ground. Without this the weather column claims the width
     of its longest sentence, which alone pushes the whole row onto a second
     line and undoes what the single row was for. */
  min-width: 0;
  flex: 0 1 auto;
  overflow: hidden;
}

/* The notes give way before the figures do. Each keeps its label and its
   number whatever the window, and loses its tail first. */
.facts dt, .facts dd:not(.sub) { flex: 0 0 auto; }
.facts dd.sub { flex: 0 1 auto; min-width: 0; }

.facts .sub {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.facts dt {
  margin: 0;
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

.facts dd {
  margin: 0;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

.facts .sub {
  font-size: 10px;
  line-height: 1.3;
}

.sub, .empty { color: var(--muted); }

.langs { display: flex; gap: 4px; margin: 0; }

.langs button {
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  padding: 3px 7px;
  font: 11px/1.2 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: 0.06em;
  cursor: pointer;
}

.langs button.on {
  background: var(--pine);
  color: var(--paper);
  border-color: var(--pine);
}

/* Blocks */

.block {
  background: var(--card);
  border: 1px solid var(--line);
  padding: 16px 18px;
}

.head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 12px;
}

h2 {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
}

.head .sub { margin: 0; font-size: 12px; font-variant-numeric: tabular-nums; }

/* Board */

.board {
  display: grid;
  grid-template-columns: minmax(0, 1.85fr) minmax(0, 1fr);
  gap: 24px;
  align-items: start;
}

.side, .main-col {
  display: flex;
  flex-direction: column;
  gap: 24px;
  min-width: 0;
}

.live, .place { padding: 0; }

/* Two of these were narrow because they sat in a side column that no longer
   exists. Their text has no business running the width of the screen. */
.bulletin > *:not(.shot), .sequence > * { max-width: 680px; }

/* Narrower than the column and centred. At full width the webcam alone was
   taller than the room left under the bar, so its own section could not be
   shown whole, which is the one thing a page like this owes a reader. */
/* Wider than it was, because what is in it changed. Six hundred and twenty
   pixels were enough for a bare camera: the picture was a slope, and a slope
   reads at any size. The broadcast carries writing — the name of what just
   passed, the track playing, the clock — and writing has a size below which it
   is not writing any more. The second term keeps the old promise: whatever the
   width, the player still has to fit under the bar without scrolling. */
.live video, .live iframe {
  width: min(100%, 980px, (100vh - 200px) * 16 / 9);
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  background: #000;
  display: block;
  border: 0;
}

.live [hidden] { display: none; }

.live-link {
  width: min(100%, 980px, (100vh - 200px) * 16 / 9);
  margin: 10px auto 0;
  text-align: right;
}

.live-link a { color: var(--muted); text-decoration: none; border-bottom: 1px solid var(--hair); }
.live-link a:hover { color: var(--ink); border-color: var(--ink); }

.frame {
  position: relative;
  width: min(100%, 380px);
  margin: 0 auto;
  aspect-ratio: 4 / 3;
}

#map {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  outline: none;
  background: var(--hair);
}

.cap {
  position: absolute;
  z-index: 500;
  left: 8px;
  bottom: 8px;
  margin: 0;
  padding: 3px 8px;
  background: rgba(244, 241, 234, 0.92);
  font-size: 11px;
  color: var(--muted);
}

.zooms {
  position: absolute;
  z-index: 500;
  top: 8px;
  left: 8px;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.zooms button {
  width: 26px;
  height: 26px;
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink);
  font: 12px/1 ui-sans-serif, system-ui, sans-serif;
  cursor: pointer;
}

.zooms button.on {
  background: var(--pine);
  color: var(--paper);
  border-color: var(--pine);
}

/* Weather bulletin */

.bulletin .words {
  margin: 0 0 10px;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.015em;
}

.bulletin img {
  width: 100%;
  display: block;
  border: 1px solid var(--hair);
  background: var(--hair);
}

.bulletin .sub { margin: 9px 0 0; font-size: 12px; font-variant-numeric: tabular-nums; }

/* Around */

.carousel {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) 30px;
  gap: 6px;
  align-items: center;
}

.carousel img {
  width: 100%;
  height: 130px;
  object-fit: cover;
  display: block;
  background: var(--hair);
}

.carousel button {
  height: 30px;
  border: 1px solid var(--line);
  background: var(--card);
  color: var(--ink);
  font-size: 17px;
  cursor: pointer;
}

.sequence a { color: var(--pine); }

/* History */

.history-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
}

.history-head h2 { margin: 0; }

.count {
  margin: 0;
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.score {
  margin: 0;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

/* Une lecture dite fausse reste dans le registre, mais l'œil ne doit pas la
   compter comme une observation : grisée, et son libellé barré. */
tr.wrong { opacity: 0.45; }

tr.wrong .event { text-decoration: line-through; }
/* Le nom barré, mais pas ce qu'il y avait vraiment : barrer la vérité avec
   l'erreur rendrait la ligne illisible et la correction inutile. */
tr.wrong .event .sub { text-decoration: none; display: block; }

.filters { display: flex; flex-wrap: wrap; gap: 4px; margin-left: auto; }

.filters button {
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  padding: 4px 11px;
  font: 12px/1.2 ui-sans-serif, system-ui, sans-serif;
  cursor: pointer;
}

.filters button.on {
  background: var(--pine);
  color: var(--paper);
  border-color: var(--pine);
}

.log {
  width: 100%;
  border-collapse: collapse;
}

.log th {
  text-align: left;
  padding: 0 10px 7px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
}

.log td {
  border-bottom: 1px solid var(--hair);
  vertical-align: middle;
  padding: 7px 10px;
}

.log tbody tr:last-child td { border-bottom: 0; }

.log .when {
  width: 8rem;
  font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
  font-variant-numeric: tabular-nums;
  font-size: 12px;
}

.log .when time { display: block; font-weight: 600; letter-spacing: -0.02em; }
.log .when span { color: var(--muted); font-size: 10.5px; letter-spacing: 0.02em; }

.log .event {
  font-size: 14px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.log .place {
  width: 11rem;
  color: var(--muted);
  font-size: 12.5px;
}

.log .shot { width: 340px; }

.log img, .log .placeholder {
  width: 320px;
  height: 180px;
  object-fit: contain;
  display: block;
  background: var(--hair);
}

/* À trancher */

.doubt h3 {
  margin: 22px 0 6px;
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

.doubt h3:first-of-type { margin-top: 0; }
.control .sub { margin: 0 0 12px; }

.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 18px;
}

.card {
  margin: 0;
  border: 1px solid var(--hair);
  border-radius: 4px;
  overflow: hidden;
}

.card img, .card .placeholder {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: contain;
  display: block;
  background: var(--hair);
}

.card figcaption {
  display: grid;
  gap: 4px;
  padding: 8px 10px 10px;
  font-size: 0.9rem;
}

.card .when, .card .place { color: var(--muted); }
.card .guess { font-weight: 600; }

/* Une carte déjà tranchée s'efface sans disparaître : on doit pouvoir revenir
   sur un avis, et la retirer ôterait le moyen de se corriger. */
.card.judged { opacity: 0.5; }

/* Une tache écartée : la question posée dessous n'est pas la même, et la carte
   doit le dire avant qu'on ait lu les boutons. */
.card.missed .guess { font-weight: 400; font-style: italic; color: var(--muted); }
.card.missed { border-style: dashed; }

.verdict {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 6px 0 0;
}

.verdict a {
  border: 1px solid var(--hair);
  border-radius: 3px;
  padding: 3px 8px;
  font-size: 0.85rem;
  text-decoration: none;
  color: var(--muted);
}

.verdict a:hover { color: var(--ink); border-color: var(--ink); }
.verdict a.on { color: var(--ink); border-color: var(--ink); font-weight: 600; }
/* Ce que la machine a lu. Un point devant le mot, pas une couleur : il ne
   s'agit pas d'appuyer sur sa réponse mais de la désigner, pour qu'on sache
   lequel des neuf boutons veut dire « c'est juste ». */
.verdict a.lu::before { content: "• "; opacity: 0.75; }
.verdict a.lu { border-style: dashed; }

/* Pipeline */

.steps {
  list-style: none;
  margin: 0;
  padding: 0;
}

.steps li {
  display: grid;
  grid-template-columns: 5rem minmax(0, 1fr);
  gap: 10px;
  padding: 6px 0;
  border-top: 1px solid var(--hair);
  color: var(--muted);
}

.steps strong { font-weight: 600; color: var(--ink); }

/* Loupe */

#loupe {
  position: fixed;
  z-index: 40;
  pointer-events: none;
  background: var(--card);
  border: 1px solid var(--ink);
  /* Le cadre entier et, contre lui, la découpe. Rien d'écrit entre les deux :
     la ligne ou la carte au-dessous porte déjà l'heure, le mot et le lieu. */
  display: flex;
  align-items: flex-start;
  gap: 1px;
}

/* Poser « display » ici oblige à redire comment on se cache : la règle du
   navigateur pour l'attribut « hidden » ne pèse rien face à un identifiant, et
   sans cette ligne la loupe s'ouvre une fois et ne se referme plus. */
#loupe[hidden] { display: none; }

#loupe img.frame {
  display: block;
  width: min(560px, 62vw);
  height: auto;
  max-height: 72vh;
  object-fit: contain;
}

/* La découpe fait deux cents pixels de côté : on lui en donne deux cent
   quarante, un agrandissement modeste qui montre ce qu'elle a sans prétendre
   à des détails qu'elle n'a pas. */
#loupe img.near {
  display: block;
  width: min(240px, 26vw);
  height: auto;
  max-height: 72vh;
  object-fit: contain;
  background: var(--hair);
}

#loupe img.near[hidden] { display: none; }

.relief .stage { position: relative; }

#relief {
  position: relative;
  width: min(100%, 620px);
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  background: #1d2b3f;
  overflow: hidden;
  cursor: grab;
}

#relief .osm {
  position: absolute;
  z-index: 2;
  left: 8px;
  bottom: 8px;
  padding: 3px 8px;
  border-radius: 999px;
  background: rgba(12, 18, 28, 0.55);
  color: #f2f5f8;
  font: 11px/1.2 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: 0.02em;
  text-decoration: none;
}

#relief:active { cursor: grabbing; }
#relief canvas { display: block; position: relative; z-index: 0; }

.relief .stage:fullscreen {
  aspect-ratio: auto;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
}

.relief .stage:fullscreen #relief { aspect-ratio: auto; }

.relief .wake {
  position: absolute;
  left: 50%;
  bottom: 12px;
  transform: translateX(-50%);
  border: 0;
  border-radius: 999px;
  padding: 6px 14px;
  background: rgba(16, 24, 34, 0.72);
  color: #f2f5f8;
  font: 11px/1.2 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: 0.04em;
  cursor: pointer;
}

.relief .stage.awake #relief { outline: 2px solid var(--pine); outline-offset: -2px; }

.relief .tools {
  /* Over the view, not above it: in full screen everything outside the stage
     is gone, and the button that puts the camera back where the webcam looks
     is the one thing you need most once you have turned the scene around. */
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  display: flex;
  gap: 6px;
}

#relief-serein, #relief-cannes, #relief-back, #relief-wide {
  padding: 3px 9px;
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: 999px;
  background: rgba(12, 18, 28, 0.5);
  color: #fff;
  font: inherit;
  font-size: 11px;
  cursor: pointer;
}

#relief-serein.on, #relief-cannes.on { background: rgba(255, 255, 255, 0.28); }
.relief .note {
  margin: 8px 0 0;
  color: var(--ink-dim, #5c6570);
  font-size: 13px;
  line-height: 1.45;
}
.relief .cap em { font-style: normal; font-weight: 600; }

.foot {
  padding: 18px 0 28px;
  border-top: 1px solid var(--line);
  margin: 28px auto 0;
  width: min(1180px, calc(100% - 48px));
}

.foot p {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin: 0;
  font-size: 13px;
}

.foot .tag {
  padding: 1px 7px;
  border: 1px solid var(--ink);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}

.box a, .foot a {
  color: var(--pine);
}

/* Turning the pages of the log */

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  margin-top: 12px;
  color: var(--muted);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}

.pager button {
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  padding: 4px 12px;
  font: 11px/1.2 ui-sans-serif, system-ui, sans-serif;
  cursor: pointer;
}

.pager button:hover:not(:disabled) { border-color: var(--pine); color: var(--pine); }
.pager button:disabled { color: var(--muted); border-color: var(--hair); cursor: default; }

/* Dataviz */

.figures .panels {
  display: grid;
  grid-template-columns: 2.4fr 1fr;
  gap: 26px;
  align-items: end;
}

.figures figure { margin: 0; min-width: 0; }

.figures figcaption {
  margin-bottom: 10px;
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  margin: 0 0 16px;
  font-size: 11px;
  color: var(--muted);
}

.legend .key { display: inline-flex; align-items: center; gap: 6px; }
.legend .key i { width: 9px; height: 9px; border-radius: 2px; }
.legend .key b { color: var(--ink); font-variant-numeric: tabular-nums; }

.bars {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 150px;
}

.bars.wide { gap: 8px; }

.bar {
  flex: 1;
  min-width: 0;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: stretch;
  gap: 3px;
}

/* The share is printed above the bar and the hour below it, so the column
   itself is only ever the measurement. A figure written inside a bar has to
   be readable against seven different colours, which no one colour is. */
.bar .val {
  font-size: 9px;
  font-weight: 400;
  text-align: center;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.bar .col {
  display: flex;
  flex-direction: column-reverse;
  min-height: 1px;
  border-radius: 2px 2px 0 0;
  overflow: hidden;
}

.bar .col i { display: block; min-height: 1px; }
.bar:hover .col { outline: 1px solid var(--ink); outline-offset: 1px; }

.bar .tick {
  font-size: 9px;
  text-align: center;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 980px) {
  .figures .panels { grid-template-columns: 1fr; }
  .bars { height: 120px; }

  .top-inner { align-items: flex-start; flex-wrap: wrap; gap: 16px; }
  /* On a narrow screen the readings may take a second line again. Height is
     cheap there and width is not: kept on one line they would be trimmed to
     the label, which says nothing. */
  .facts { flex-wrap: wrap; overflow: visible; }
  .facts > div { overflow: visible; }
  .facts { margin-left: 0; }
  .facts > div:first-child { padding-left: 0; border-left: 0; }
  .board { grid-template-columns: 1fr; }
  .steps { grid-template-columns: 1fr; }
  .filters { margin-left: 0; }
}

/* Getting about the page */

.skip {
  position: absolute;
  left: -9999px;
  z-index: 2000;
  padding: 10px 16px;
  background: var(--pine);
  color: var(--paper);
  border-radius: 0 0 8px 0;
}

.skip:focus { left: 0; top: 0; }

.sr {
  /* Read aloud, never drawn: every section owes its name to a heading, and a
     page whose headings are only pictures cannot be navigated by ear. */
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.onpage {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
}

.onpage a {
  position: relative;
  padding: 11px 8px 10px;
  color: var(--muted);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
}

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

/* The section being read, underlined. Nothing moves and nothing is added to
   the page when it changes: a bar that grew or shrank would drag the eye away
   from the webcam, which is the one thing here worth looking at. */
.onpage a::after {
  content: "";
  position: absolute;
  left: 13px;
  right: 13px;
  bottom: 0;
  height: 2px;
  background: var(--pine);
  opacity: 0;
  transition: opacity 0.2s;
}

.onpage a[aria-current="true"] { color: var(--ink); }
.onpage a[aria-current="true"]::after { opacity: 1; }

@media (max-width: 640px) {
  .onpage { overflow-x: auto; flex-wrap: nowrap; }
  .onpage a { white-space: nowrap; }
}

.log .event .sub {
  display: block;
  margin-top: 3px;
  color: var(--muted);
  font-size: 11px;
  line-height: 1.5;
}

.bulletin .shot {
  position: relative;
  /* Smaller: this is a thumbnail of the sky, not the view itself, which is
     already playing live at the top of the page. Capped rather than given a
     share of the width, since this card now has the whole page to spread in. */
  width: min(62%, 330px);
  min-width: 190px;
  margin: 8px 0 2px;
}

.bulletin .shot img { display: block; width: 100%; border-radius: 3px; }

.bulletin .shot .moon {
  position: absolute;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border: 1px solid rgba(255, 255, 255, 0.85);
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35);
}

a.out {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--line);
}

a.out:hover, a.out:focus-visible { border-bottom-color: currentColor; }

section[id] { scroll-margin-top: 50px; }

.anchor {
  margin-left: 6px;
  color: var(--line);
  font-size: 12px;
  text-decoration: none;
  opacity: 0;
  transition: opacity 0.15s;
}

.head:hover .anchor, .history-head:hover .anchor, .anchor:focus-visible { opacity: 1; }

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

#theme {
  min-width: 30px;
  font-size: 12px;
}

/* The pipeline, drawn */

.chart { padding: 14px 16px 4px; }

.chart .flow {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 6px;
}

.chart .asks {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 10px 0 0;
}

.chart .lab {
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.chart .join {
  padding: 3px 9px;
  border: 1px dashed var(--line);
  border-radius: 999px;
  color: var(--muted);
  font-size: 11px;
}

.chart .step {
  flex: 1 1 96px;
  position: relative;
  padding: 9px 10px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--shade);
}

.chart .flow .step + .step::before {
  /* The arrow lives on the box that follows, so the last box has none. */
  content: "";
  position: absolute;
  left: -6px;
  top: 50%;
  width: 6px;
  border-top: 1px solid var(--line);
}

.chart .step b {
  display: block;
  font-size: 11px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.chart .step span { color: var(--muted); font-size: 11px; }

.chart .step.out { border-color: var(--pine); background: none; }
.chart .step.out b { color: var(--pine); }

.screen {
  padding: 0;
  background: none;
  border: 0;
}

.around {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) minmax(360px, 1.55fr) minmax(220px, 1fr);
  gap: 14px;
  align-items: start;
}

.around .stage { grid-column: 2; grid-row: 1; }
.around #pipeline { grid-column: 1; grid-row: 1; }
.around #rebuild { grid-column: 3; grid-row: 1; }
.around #numbers { grid-column: 1 / 3; grid-row: 2; }
.around #music { grid-column: 3; grid-row: 2; }

.box {
  background: var(--card);
  border: 1px solid var(--line);
  padding: 14px 16px;
}

.box p {
  margin: 0 0 10px;
  font-size: 13px;
  line-height: 1.5;
}

.box p:last-child { margin-bottom: 0; }

.box p strong { letter-spacing: 0.03em; }

.live-hold {
  position: relative;
  width: 100%;
  margin: 0;
}

.live-hold::before {
  content: "";
  display: block;
  aspect-ratio: 16 / 9;
}

.screen .stage-frame {
  position: absolute;
  inset: 0;
}

.screen .stage-frame iframe,
.screen .stage-frame video {
  width: 100%;
  height: 100%;
  margin: 0;
  aspect-ratio: auto;
  background: #000;
  display: block;
  border: 0;
}

.screen .stage-frame [hidden] { display: none; }

/* Au-dessus des commandes du lecteur, pour qu'un doigt sur la tablette
   atteigne encore la barre. Le texte ne prend pas les touches. */
.degrade {
  position: absolute;
  z-index: 4;
  left: 14px;
  bottom: 56px;
  max-width: min(420px, calc(100% - 28px));
  margin: 0;
  padding: 8px 10px 9px;
  background: rgba(12, 14, 16, 0.78);
  border-top: 2px solid #f0b429;
  color: #f7f4ee;
  font-size: 13px;
  line-height: 1.35;
  pointer-events: none;
}

.degrade span {
  display: block;
  margin-bottom: 2px;
  color: #f0b429;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.live-chip.degraded {
  color: #c9842a;
  border-color: color-mix(in srgb, #c9842a 40%, var(--line));
}

.live-chip.degraded i { animation: none; }

.around .chips {
  margin-top: 10px;
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px;
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.chip i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}

.live-chip { color: #e24b4b; border-color: color-mix(in srgb, #e24b4b 35%, var(--line)); }
.live-chip i { animation: pulse 1.2s steps(2) infinite; }
.pi-chip { color: #1aa8b5; border-color: color-mix(in srgb, #1aa8b5 35%, var(--line)); }
:root[data-theme="dark"] .pi-chip { color: #46d4e0; }

@keyframes pulse {
  50% { opacity: 0.15; }
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0;
}

.play {
  appearance: none;
  border: 0;
  background: var(--pine);
  color: var(--paper);
  padding: 7px 13px;
  font: 600 12px/1.2 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: 0.02em;
  text-decoration: none;
  cursor: pointer;
}

.play.ghost {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--line);
}

.play.on { background: var(--pine); color: var(--paper); }

.hash-frame {
  position: relative;
  padding: 22px;
}

.hash-inner { position: relative; z-index: 1; }

.hash-strip {
  position: absolute;
  z-index: 2;
  display: block;
  pointer-events: none;
  image-rendering: pixelated;
}

.hash-top, .hash-bot {
  left: 22px;
  right: 22px;
  height: 18px;
}

.hash-top { top: 2px; }
.hash-bot { bottom: 2px; }

.hash-side {
  top: 22px;
  bottom: 22px;
  width: 18px;
}

.hash-left { left: 2px; }
.hash-right { right: 2px; }

.hash-on-video {
  width: min(100%, 1280px, (100vh - 150px) * 16 / 9);
  margin: 0 auto;
  padding: 0;
}

.hash-on-video .live-hold { width: 100%; }

.hash-on-video .hash-top,
.hash-on-video .hash-bot {
  left: 0;
  right: 0;
  height: 20px;
}

.hash-on-video .hash-top { top: 0; }
.hash-on-video .hash-bot { bottom: 0; }

.hash-on-video .hash-side {
  top: 0;
  bottom: 0;
  width: 20px;
}

.hash-on-video .hash-left { left: 0; }
.hash-on-video .hash-right { right: 0; }

.quiet { color: var(--muted); font-size: 12px; text-decoration: none; }
.quiet:hover { color: var(--ink); }

.effects {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
}

.effects th,
.effects td {
  padding: 5px 8px 5px 0;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--hair);
}

.effects th {
  color: var(--muted);
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 600;
}

.effects td:first-child {
  width: 56px;
  padding-right: 10px;
  overflow: visible;
}

.effects img {
  display: block;
  width: 56px;
  height: 32px;
  object-fit: cover;
  background: #111;
  transform-origin: left center;
  transition: transform 0.12s ease;
  position: relative;
}

.effects tr:hover img,
.effects tr:focus-within img {
  transform: scale(5);
  z-index: 8;
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
}

.numbers { overflow: visible; }

.effects td:nth-child(2) {
  white-space: nowrap;
  font-weight: 600;
}

@media (max-width: 1400px) {
  .around {
    display: flex;
    flex-direction: column;
  }
  .around .stage { order: -1; width: 100%; }
}

.feature .feature-line {
  max-width: 68ch;
  font-size: 18px;
  letter-spacing: -0.02em;
  line-height: 1.45;
}

.feature-steps {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 18px 0 0;
  padding: 0;
}

.feature-steps p {
  flex: 1 1 160px;
  margin: 0;
  padding: 12px 14px;
  border: 1px solid var(--pine);
  background: var(--shade);
}

.feature-steps p strong {
  display: block;
  margin-bottom: 4px;
  font-size: 15px;
  letter-spacing: 0.04em;
}

.feature-steps p span { color: var(--muted); font-size: 13px; }

.feature .hash-frame { margin-bottom: 20px; }
.feature .feature-still { margin-top: 0; }

.feature-still { margin: 0; max-width: 720px; }
.feature-still img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  background: #111;
}
.feature-still figcaption {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--muted);
}

.story p {
  max-width: 68ch;
  font-size: 15px;
  line-height: 1.55;
}

.story .lead {
  font-size: 18px;
  letter-spacing: -0.02em;
  color: var(--ink);
}

.stills {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 18px 16px;
}

.stills figure { margin: 0; }
.stills img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  background: #111;
}
.stills figcaption {
  margin: 8px 0 0;
  font-size: 12px;
  color: var(--muted);
  line-height: 1.45;
}

.wiki p {
  max-width: 68ch;
  font-size: 15px;
  line-height: 1.55;
}

.wiki h3 {
  margin: 28px 0 8px;
  font-size: 11px;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  color: var(--muted);
}
