/*
 * Stratforth website stylesheet: the one stylesheet for every page.
 *
 * Tokens and rules follow docs/design/design-language.md; change the document first, then
 * this file. The build publishes it as site/assets/site.<hash>.css (cached for a year). Map
 * positions live in the generated map-europe.css, loaded only by pages with a map.
 *
 * Sections:
 *   1 tokens, 2 base, 3 layout, 4 header and footer, 5 type helpers, 6 buttons,
 *   7 bands and headings, 8 home intro, 9 operations console (bar, map, pins, rail),
 *   10 flow, 11 modules, 12 split bands and fact lists, 13 closing call to action,
 *   14 page heads, 15 switcher views, 16 platform stages, 17 use cases, 18 tenant drawing,
 *   19 FAQ, facts and text pages,
 *   20 states set by site.js, 21 motion, 22 narrow screens, 23 base breakpoints and print.
 *
 * States written by src/assets/site.js are prefixed "is-". Everything must also look finished
 * without the script.
 */

/* 1. Tokens ------------------------------------------------------------------------------------ */

/* Self-hosted typefaces (OFL; see docs/README.md, "Fonts"). Variable fonts: one file covers
   every weight used. Latin subset from Google Fonts. */
@font-face {
  font-family: "Geist";
  src: url("/fonts/geist-v5-latin-var.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Geist Mono";
  src: url("/fonts/geist-mono-v6-latin-var.woff2") format("woff2");
  font-weight: 400 500;
  font-style: normal;
  font-display: swap;
}

:root {
  --paper: #f3f3f1;
  --surface: #ffffff;
  --sunken: #eaeae7;
  --ink: #121316;
  --ink-2: #45484e;
  --ink-3: #62666d;
  --rule: #d8d9d5;
  --rule-strong: #868985; /* 3.5:1 on white, 3.2:1 on paper: meets the 3:1 non-text minimum */
  --accent: #ee5a1f;
  --accent-ink: #b43f0e;
  /* Risk areas on the field-operations map: muted, so the accent stays the one strong colour.
     As label text on white they are 6.0:1 and 5.0:1. */
  --zone-high: #a3463f;
  --zone-restricted: #8c6a1a;

  --font-sans: "Geist", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas,
    "Liberation Mono", monospace;

  --step-label: 0.75rem;
  --step-small: 0.875rem;
  --step-body: 1.0625rem;
  --step-lead: clamp(1.125rem, 1rem + 0.5vw, 1.3125rem);
  --step-h3: 1.25rem;
  --step-h2: clamp(1.625rem, 1.3rem + 1.2vw, 2.25rem);
  --step-h1: clamp(2.25rem, 1.6rem + 2.8vw, 3.75rem);

  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 24px;
  --s-6: 32px;
  --s-7: 48px;
  --s-8: 64px;
  --s-9: 96px;

  --content: 1200px;
  --gutter: 24px;
  --measure: 68ch;
  --hairline: 1px solid var(--rule);
}

/* 2. Base -------------------------------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--step-body);
  line-height: 1.6;
  overflow-wrap: break-word;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 600;
  line-height: 1.15;
  text-wrap: balance;
}

h1 {
  font-size: var(--step-h1);
  line-height: 1.05;
  letter-spacing: -0.02em;
}

h2 {
  font-size: var(--step-h2);
  letter-spacing: -0.015em;
}

h3 {
  font-size: var(--step-h3);
  line-height: 1.3;
  letter-spacing: -0.005em;
}

p,
ul,
ol,
dl,
figure,
blockquote {
  margin: 0;
}

p + p {
  margin-top: var(--s-4);
}

img,
svg {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: var(--ink);
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

a:hover {
  text-decoration-thickness: 2px;
}

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

code,
kbd,
samp {
  font-family: var(--font-mono);
  font-size: 0.9em;
}

strong {
  font-weight: 600;
}

/* Keep the hidden attribute authoritative even where a class sets display. */
[hidden] {
  display: none !important;
}

.skip-link {
  position: absolute;
  left: var(--s-4);
  top: -100px;
  z-index: 10;
  padding: var(--s-2) var(--s-4);
  background: var(--ink);
  color: var(--surface);
  font-family: var(--font-mono);
  font-size: var(--step-small);
}

.skip-link:focus {
  top: var(--s-4);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* 3. Layout ------------------------------------------------------------------------------------ */

.container {
  width: 100%;
  max-width: calc(var(--content) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 0 var(--gutter);
}

.prose {
  max-width: var(--measure);
}

.prose > * + * {
  margin-top: var(--s-4);
}

.prose h2 {
  margin-top: var(--s-7);
}

.prose h3 {
  margin-top: var(--s-6);
}

.prose ul,
.prose ol {
  padding-left: 1.25em;
}

.prose li + li {
  margin-top: var(--s-2);
}

/* 4. Header and footer ------------------------------------------------------------------------- */

.site-header {
  border-bottom: var(--hairline);
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--s-6);
  min-height: 64px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--ink);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
}

.brand svg {
  width: 20px;
  height: 20px;
}

.site-nav {
  flex: 1 1 auto;
  min-width: 0;
}

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--ink-2);
  font-size: 0.9375rem;
  text-decoration: none;
}

.site-nav a:hover,
.site-nav a[aria-current="page"] {
  color: var(--ink);
}

.site-nav a[aria-current="page"] {
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 6px;
}

.site-header__cta {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  margin-left: auto;
  padding: 0 var(--s-4);
  background: var(--ink);
  color: var(--surface);
  font-family: var(--font-mono);
  font-size: var(--step-label);
  font-weight: 500;
  letter-spacing: 0.08em;
  text-decoration: none;
  text-transform: uppercase;
  white-space: nowrap;
}

.site-header__cta:hover {
  background: #2a2c31;
}

.site-footer {
  border-top: var(--hairline);
  font-size: var(--step-small);
}

.site-footer__top {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  padding: var(--s-7) 0 var(--s-6);
}

.site-footer ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer a {
  color: var(--ink-2);
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--ink);
  text-decoration: underline;
}

.site-footer__legal {
  padding: var(--s-3) 0;
  border-top: var(--hairline);
  color: var(--ink-3);
  font-size: var(--step-label);
}

.site-footer__base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-4) 0 var(--s-6);
  border-top: var(--hairline);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: var(--step-label);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.site-footer__base a {
  color: var(--ink-3);
  text-transform: none;
  letter-spacing: 0;
}

/* 5. Type helpers ------------------------------------------------------------------------------ */

.label {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: var(--step-label);
  font-weight: 400;
  letter-spacing: 0.08em;
  line-height: 1.4;
  text-transform: uppercase;
}

/* A small square marker before a label; the accent variant marks attention. */
.label--marked::before {
  content: "";
  width: 6px;
  height: 6px;
  background: var(--ink);
}

.label--attention::before {
  background: var(--accent);
}

.lead {
  max-width: 62ch;
  color: var(--ink-2);
  font-size: var(--step-lead);
  line-height: 1.5;
}

.muted {
  color: var(--ink-3);
}

.mono {
  font-family: var(--font-mono);
}

/* 6. Buttons ----------------------------------------------------------------------------------- */

.button-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3);
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 44px;
  padding: var(--s-3) var(--s-5);
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--surface);
  font-family: var(--font-mono);
  font-size: var(--step-label);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-decoration: none;
  text-transform: uppercase;
}

.button:hover {
  background: #2a2c31;
}

.button--secondary {
  background: transparent;
  color: var(--ink);
}

.button--secondary:hover {
  background: var(--surface);
}

/* 7. Bands and headings ------------------------------------------------------------------------ */

.band {
  padding: 112px 0;
  border-top: var(--hairline);
}

.band--surface {
  background: var(--surface);
}

.band__head {
  display: grid;
  gap: var(--s-3);
  max-width: 760px;
  margin-bottom: var(--s-7);
}

.band__head--split {
  max-width: none;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  align-items: end;
  gap: var(--s-3) var(--s-7);
}

.band h2,
.closing h2 {
  font-size: clamp(2rem, 1.3rem + 2.2vw, 3.125rem);
  font-weight: 600;
  line-height: 1.04;
  letter-spacing: -0.035em;
}

.band__head .label + h2 {
  margin-top: var(--s-1);
}

.band__head .email-big {
  margin-top: var(--s-3);
}

/* A line or two under a band's figure. */
.band__after {
  max-width: 62ch;
  margin-top: var(--s-5);
  color: var(--ink-2);
}

.band__note {
  max-width: 44ch;
  color: var(--ink-2);
  font-size: 1.0625rem;
}

/* 8. Home: intro ------------------------------------------------------------------------------- */

.intro {
  padding: var(--s-7) 0 var(--s-7);
}

.intro__copy {
  display: grid;
  grid-template-columns: minmax(0, 6fr) minmax(0, 5fr);
  gap: var(--s-4) var(--s-7);
  align-items: end;
  margin-bottom: var(--s-6);
}

.intro__copy .label {
  grid-column: 1 / -1;
}

.intro h1 {
  font-size: clamp(2.75rem, 1.6rem + 3.2vw, 4.25rem);
  font-weight: 600;
  line-height: 0.98;
  letter-spacing: -0.04em;
}

.intro__lead {
  color: var(--ink-2);
  font-size: 1.125rem;
  line-height: 1.5;
}

.intro__actions,
.closing__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3) var(--s-5);
  margin-top: var(--s-5);
}

.intro__email,
.closing__email {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--ink-2);
  text-underline-offset: 4px;
}

/* 9. Operations console ------------------------------------------------------------------------ */

.ops {
  margin: 0;
  border: 1px solid var(--rule);
  background: var(--surface);
}

.ops__bar,
.ops-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.ops__bar {
  min-height: 44px;
  padding: var(--s-1) var(--s-4);
  border-bottom: var(--hairline);
}

.ops__crumbs span + span::before {
  content: "/";
  margin: 0 var(--s-2);
  color: var(--rule-strong);
}

.ops__crumbs span:last-child {
  color: var(--ink);
}

.ops__state {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin: 0;
}

.ops__live {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.ops__live::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ink-2);
}

.ops__chip {
  padding: 3px var(--s-2);
  background: var(--accent);
  color: var(--ink);
  font-weight: 500;
}

.ops__chip--quiet {
  background: var(--sunken);
  color: var(--ink-2);
}

.ops__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 340px;
}

.ops__caption {
  padding: var(--s-2) var(--s-4);
  border-top: var(--hairline);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
}

/* The map. The frame has the geography's proportions (2200 x 1600 km, 11:8; set in
   tools/europe_map.py); everything placed with
   data-at (positions in map-europe.css) is a percentage of it. A smaller box may crop it. */

.map {
  position: relative;
  overflow: hidden;
  aspect-ratio: 11 / 8;
  background: #eceeed;
}

.map__frame {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: 11 / 8;
}

.map__geo,
.map__lines {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

.map [data-at] {
  position: absolute;
}

/* Beside the rail (wide screens) the console map takes the rail's height. The frame then grows
   to cover the box, keeping its proportions and its centre, so a little of the east and west is
   cropped rather than leaving a gap under the map. cqw and cqh are the map box's own size. */
@media (min-width: 1181px) {
  .ops .map {
    container-type: size;
    aspect-ratio: auto;
    height: 100%;
    min-height: 480px;
  }

  .ops .map__frame {
    top: 50%;
    left: 50%;
    width: max(100cqw, 137.5cqh); /* 11:8, so the frame covers the box */
    transform: translate(-50%, -50%);
  }

  /* Latitude ticks follow the visible right edge, and the scale bar the frame's real width. */
  .ops .map .map__tick--right {
    left: calc(50% + 50cqw);
  }

  .ops .map__scale {
    width: calc(max(100cqw, 137.5cqh) * 0.0909);
  }

  .ops .map--sahel .map__scale {
    width: calc(max(100cqw, 137.5cqh) * 0.1299);
  }
}

.map__route {
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 1.25;
  stroke-dasharray: 5 4;
  vector-effect: non-scaling-stroke;
}

/* The truck's run, along the real motorway network. */
.map__route--road {
  stroke: var(--ink-2);
  stroke-width: 1.5;
  stroke-dasharray: none;
  stroke-linejoin: round;
}

/* The cargo flight's great circle. */
.map__route--air {
  stroke: var(--ink-3);
  stroke-dasharray: 1 4;
  stroke-linecap: round;
  stroke-width: 1.5;
}

/* The route the rule is about. */
#route-sea-esb-hum {
  stroke: var(--accent);
  stroke-width: 1.75;
}

/* The storm warning: a weather cell drawn by tools/europe_map.py as a soft glow, a dashed edge,
   inner intensity contours, a hatched core and the forecast track. It is the one thing on the
   map that needs attention, so it carries the accent (with the lane and shipment it threatens).
   Stroke widths are in screen pixels (non-scaling), so the cell stays fine at any map size. */
.map__zone path {
  vector-effect: non-scaling-stroke;
}

/* The glow and the hatched core get their blur and pattern from attributes in the SVG. */
.map__zone-glow {
  fill: rgb(238 90 31 / 0.16);
}

.map__zone-edge {
  fill: none;
  stroke: var(--accent);
  stroke-width: 1;
  stroke-dasharray: 3 3;
}

.map__zone-contour {
  fill: none;
  stroke: var(--accent);
  stroke-width: 0.75;
}

.map__zone-contour--1 {
  fill: rgb(238 90 31 / 0.07);
  stroke-opacity: 0.55;
}

.map__zone-contour--2 {
  stroke-opacity: 0.85;
}

.map__zone-hatch {
  fill: rgb(238 90 31 / 0.5);
}

.map__zone-track {
  fill: none;
  stroke: var(--accent-ink);
  stroke-width: 1;
}

.map__zone-arrow {
  fill: var(--accent-ink);
}

/* The warning's name tag (above the cell) and the time at the end of its track. */
.map__zone-tag,
.map__zone-time {
  transform: translate(-50%, -50%);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  line-height: 16px;
  text-transform: uppercase;
  white-space: nowrap;
}

.map__zone-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 1px 2px 1px 6px;
  border: 1px solid var(--accent);
  background: var(--surface);
  color: var(--ink);
}

.map__zone-tag b {
  padding: 0 5px;
  background: var(--accent);
  color: var(--ink);
  font-weight: 500;
}

.map__zone-time {
  color: var(--accent-ink);
}

.map__labels {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.map__place {
  transform: translate(-50%, -50%);
  font-family: var(--font-mono);
  text-transform: uppercase;
  white-space: nowrap;
}

.map__place--sea {
  color: var(--ink-3);
  font-size: 0.75rem;
  letter-spacing: 0.4em;
}

.map__place--country {
  color: var(--ink-3); /* 5:1 on the sea, 5.9:1 on land */
  font-size: 0.625rem;
  letter-spacing: 0.22em;
}

.map__tick {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  white-space: nowrap;
}

.map__tick--bottom {
  transform: translate(-50%, -140%);
}

.map__tick--right {
  transform: translate(calc(-100% - 6px), -50%);
}

.map__layers {
  position: absolute;
  top: var(--s-3);
  left: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border: var(--hairline);
  background: rgb(255 255 255 / 0.94);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.map__layers-title {
  margin-bottom: var(--s-1);
  color: var(--ink-3);
}

.map__layers ul {
  display: grid;
  margin: 0;
  padding: 0;
  list-style: none;
}

.layer {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 26px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-2);
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
}

.layer::before {
  content: "";
  width: 9px;
  height: 9px;
  border: 1px solid var(--ink-2);
}

.layer.is-on::before {
  background: var(--ink);
  border-color: var(--ink);
}

button.layer {
  cursor: pointer;
}

/* The layer switches double as the map's key: each carries the symbol its layer is drawn with,
   in miniature. One family on every map, so the same kind of thing has the same swatch:
   places are squares, people a ring, each mover its own solid shape, a point event a triangle,
   and an area a dashed outline with its tint or hatch. */
.key {
  position: relative;
  flex: none;
  width: 12px;
  height: 12px;
}

.key::before {
  content: "";
  position: absolute;
  inset: 1px;
  box-sizing: border-box;
}

.key--site::before {
  border: 1.5px solid var(--ink);
  background: var(--surface);
}

/* A rated site or supplier: the square with its grade inside. */
.key--rated::before {
  content: "A";
  inset: 0;
  border: 1.5px solid var(--ink);
  background: var(--surface);
  color: var(--ink);
  font-size: 7px;
  font-weight: 500;
  letter-spacing: 0;
  line-height: 9px;
  text-align: center;
}

/* Where a route ends at a place that is not a site. */
.key--place::before {
  inset: 2px;
  border: 1.5px solid var(--ink-2);
  border-radius: 50%;
}

/* People: travellers in a city, or staff at a site. */
.key--people::before {
  inset: 0;
  border: 1px solid var(--ink-2);
  border-radius: 50%;
  background: var(--surface);
}

.key--vehicle::before {
  inset: 3px 0;
  border-radius: 2px;
  background: var(--ink);
}

.key--flight::before {
  inset: 0;
  background: var(--ink);
  clip-path: polygon(0 10%, 100% 50%, 0 90%);
}

.key--vessel::before {
  inset: 1px;
  border-radius: 50%;
  background: var(--ink);
}

.key--incident::before {
  inset: 0 0 1px;
  background: var(--ink);
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

/* An area: its outline, tint and hatch. --area is its colour. */
.key--area::before {
  inset: 0;
  border: 1px dashed var(--area);
  background:
    repeating-linear-gradient(var(--hatch-angle), transparent 0 var(--hatch-gap), var(--area) var(--hatch-gap) calc(var(--hatch-gap) + 1px)),
    color-mix(in srgb, var(--area) 14%, var(--surface));
}

.key--weather {
  --area: var(--ink-3);
  --hatch-angle: 50deg;
  --hatch-gap: 2px;
}

/* An advisory is a tinted area with no hatch. */
.key--advisory::before {
  border: 1px dashed var(--accent);
  background: rgb(238 90 31 / 0.14);
}

.key--high {
  --area: var(--zone-high);
  --hatch-angle: 50deg;
  --hatch-gap: 2px;
}

.key--restricted {
  --area: var(--zone-restricted);
  --hatch-angle: 130deg;
  --hatch-gap: 3px;
}

.map__scale {
  position: absolute;
  left: var(--s-3);
  bottom: var(--s-3);
  width: 9.09%; /* 200 km of the 2200 km frame */
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  white-space: nowrap;
}

.map__scale-bar {
  display: block;
  height: 5px;
  margin-bottom: 3px;
  border: 1px solid var(--ink-2);
  border-top: 0;
}

/* Pins: each list item is a zero-size anchor at its map position; the mark is drawn around it. */

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

.pin {
  width: 0;
  height: 0;
}

.pin::before {
  content: "";
  position: absolute;
  left: -5px;
  top: -5px;
  width: 10px;
  height: 10px;
  box-sizing: border-box;
  border: 1.5px solid var(--ink);
  background: var(--surface);
}

.pin--vessel::before {
  border-radius: 50%;
  background: var(--ink);
}

/* Where a route ends at a place with no site or ring: a small open circle and a quiet name. */
.pin--dest::before {
  left: -4px;
  top: -4px;
  width: 8px;
  height: 8px;
  border: 1.5px solid var(--ink-2);
  border-radius: 50%;
}

.pin--dest .pin__label {
  left: 8px;
  background: none;
  color: var(--ink-2);
}

/* A truck: a small solid block. An aircraft: a chevron pointing along its flight. */
.pin--truck::before {
  left: -6px;
  top: -4px;
  width: 12px;
  height: 8px;
  border-radius: 2px;
  background: var(--ink);
}

/* --heading comes with the aircraft's position (map-europe.css) and is updated by site.js as
   it flies, so the chevron always points along its arc. */
.pin--aircraft::before {
  left: -6px;
  top: -6px;
  width: 0;
  height: 0;
  border: 6px solid transparent;
  border-left: 11px solid var(--ink);
  border-right: 0;
  background: none;
  transform: rotate(var(--heading, 0deg));
}

/* Travellers: a ring sized by how many of the organisation's people are in the city now, with
   the count inside and the city's name beneath. */
.pin--travellers {
  --d: 20px;
}

.pin--t1 { --d: 18px; }
.pin--t3 { --d: 20px; }
.pin--t4 { --d: 21px; }
.pin--t5 { --d: 22px; }
.pin--t6 { --d: 23px; }
.pin--t14 { --d: 28px; }

.pin--travellers::before {
  left: calc(var(--d) / -2);
  top: calc(var(--d) / -2);
  width: var(--d);
  height: var(--d);
  border: 1px solid var(--ink-2);
  border-radius: 50%;
  background: rgb(255 255 255 / 0.9);
}

.pin__count {
  position: absolute;
  left: -12px;
  top: -8px;
  width: 24px;
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 16px;
  text-align: center;
}

.pin--travellers .pin__label {
  left: 0;
  top: calc(var(--d) / 2 + 1px);
  transform: translateX(-50%);
  padding: 0;
  background: none;
  color: var(--ink-3);
  font-size: 0.5625rem;
  line-height: 12px;
}

/* Where the name would collide with a neighbour, it sits to the right of the ring instead. */
.pin--travellers.pin--label-right .pin__label {
  left: calc(var(--d) / 2 + 4px);
  top: -6px;
  transform: none;
}

.pin--attention::before {
  left: -6px;
  top: -6px;
  width: 12px;
  height: 12px;
  background: var(--accent);
  border-color: var(--ink);
}

/* The ping: two rings around the attention pin, the one place on a map that says "it is
   happening here". They stand still as drawn, and expand and fade, over and over, when motion
   is allowed (section 21). One ping per map. */
.pin--attention::after {
  content: "";
  position: absolute;
  left: -17px;
  top: -17px;
  width: 34px;
  height: 34px;
  box-sizing: border-box;
  border: 1px solid rgb(238 90 31 / 0.55);
  border-radius: 50%;
  background: radial-gradient(circle, transparent 11px, var(--accent) 11.5px, var(--accent) 12.5px, transparent 13px);
}

.pin__label {
  position: absolute;
  left: 10px;
  top: -8px;
  padding: 0 3px;
  background: rgb(255 255 255 / 0.82);
  color: var(--ink-2);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  line-height: 16px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  white-space: nowrap;
}

.pin--attention .pin__label {
  left: 14px;
  color: var(--ink);
  font-weight: 500;
}

.pin--label-left .pin__label {
  left: auto;
  right: 14px;
}

/* The pin's hit area, added by site.js: a 32px square centred on the mark. */
.pin__hit {
  position: absolute;
  left: -16px;
  top: -16px;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

/* The selected pin gets corner brackets, as in a targeting reticle. */
.pin.is-selected .pin__hit {
  --b: var(--ink);
  background:
    linear-gradient(var(--b), var(--b)) top left / 7px 1.5px,
    linear-gradient(var(--b), var(--b)) top left / 1.5px 7px,
    linear-gradient(var(--b), var(--b)) top right / 7px 1.5px,
    linear-gradient(var(--b), var(--b)) top right / 1.5px 7px,
    linear-gradient(var(--b), var(--b)) bottom left / 7px 1.5px,
    linear-gradient(var(--b), var(--b)) bottom left / 1.5px 7px,
    linear-gradient(var(--b), var(--b)) bottom right / 7px 1.5px,
    linear-gradient(var(--b), var(--b)) bottom right / 1.5px 7px;
  background-repeat: no-repeat;
  /* Where the hit area is enlarged for touch (by padding), the brackets keep their 32px size. */
  background-origin: content-box;
}

/* A callout: a small box on the map joined to its pin by a dotted leader line, as if the pin had
   just been clicked. The home page uses one for the passenger list of a flight. The leader is a
   line in the generated overlay (tools/europe_map.py) and meets the box's top edge 16px in from
   its right corner, which is the point the box is positioned by. */
.map__leader {
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 1;
  stroke-dasharray: 1 3;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

.manifest {
  width: 208px;
  padding: 0 var(--s-3) 6px;
  border: 1px solid var(--ink);
  background: var(--surface);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  line-height: 1.6;
  transform: translate(calc(-100% + 16px), 0);
}

.manifest p {
  display: flex;
  justify-content: space-between;
  gap: var(--s-3);
  margin: 0;
  text-transform: uppercase;
}

.manifest__head {
  padding: 5px 0;
  border-bottom: var(--hairline);
}

.manifest__head span:first-child {
  color: var(--ink);
  font-weight: 500;
}

.manifest__list {
  margin: 0;
  padding: 5px 0;
  list-style: none;
}

.manifest__list li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
}

.manifest__list span:first-child {
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 0.75rem;
  letter-spacing: 0;
}

.manifest__status {
  padding-top: 5px;
  border-top: var(--hairline);
  color: var(--ink-2);
}

/* Rail panels: inspector, decision, activity. */

.ops__rail {
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr);
  border-left: var(--hairline);
  min-width: 0;
}

.ops-panel {
  padding: 0 var(--s-4) var(--s-4);
  border-bottom: var(--hairline);
}

.ops-panel:last-child {
  border-bottom: 0;
}

/* site.js parks focus on the inspector while a replay runs (see setupDecision). */
.ops-panel[tabindex="-1"]:focus {
  outline: none;
}

.ops-panel__head {
  min-height: 36px;
  margin: 0 calc(-1 * var(--s-4)) var(--s-3);
  padding: 0 var(--s-4);
  border-bottom: var(--hairline);
}

.inspect__title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--s-2);
  margin-bottom: var(--s-2);
  font-size: 0.9375rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.inspect__title span {
  color: var(--ink-3);
  font-size: 0.8125rem;
  font-weight: 400;
}

.inspect__rows {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  margin: 0;
  font-size: 0.8125rem;
}

.inspect__rows dt,
.inspect__rows dd {
  margin: 0;
  padding: 5px 0;
  border-top: var(--hairline);
}

.inspect__rows dt {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  line-height: 1.8;
}

.inspect__rows .is-attention {
  color: var(--accent-ink);
  font-weight: 500;
}

/* Tall enough for either state (the two choices, or the outcome and "Replay"), so taking the
   decision does not change the rail's height and with it the size of the map. */
.ask {
  min-height: 208px;
}

.ask__question {
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.4;
}

.ask__why {
  margin-top: var(--s-1);
  text-wrap: balance; /* no single word left alone on the last line */
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
}

.ask__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin-top: var(--s-3);
}

.ask__button {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 0 var(--s-3);
  border: 1px solid var(--ink);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.ask__button--primary {
  background: var(--ink);
  color: var(--surface);
}

button.ask__button {
  cursor: pointer;
}

button.ask__button:hover {
  background: var(--sunken);
}

button.ask__button--primary:hover {
  background: #2a2c31;
}

.ask__done {
  margin-top: var(--s-3);
  font-size: 0.8125rem;
  line-height: 1.45;
}

.ask__replay {
  margin-top: var(--s-2);
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-2);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-decoration: underline;
  text-transform: uppercase;
  text-underline-offset: 3px;
  cursor: pointer;
}

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

.activity__item {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  gap: var(--s-2);
  padding: 6px 0 6px var(--s-2);
  border-top: var(--hairline);
  border-left: 2px solid transparent;
  font-size: 0.8125rem;
  line-height: 1.4;
}

.activity__item:first-child {
  border-top: 0;
}

.activity__item time {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  line-height: 1.65;
}

.activity__item--attention {
  border-left-color: var(--accent);
  background: rgb(238 90 31 / 0.06);
}

.activity__item--attention time {
  color: var(--accent-ink);
}

/* A list of people and where each stands (the check-ins): the name, then the state on the right.
   One row per person, so the rows add up to the tally in the panel's head. The rows are set
   tightly so that six of them and the note fit the rail without making the map taller. */
.activity--people {
  padding-bottom: var(--s-2);
}

.activity--people .activity__item {
  grid-template-columns: minmax(0, 1fr) auto;
  padding-block: 3px;
}

.activity__state {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  line-height: 1.65;
  text-transform: uppercase;
}

.activity__item--attention .activity__state {
  color: var(--accent-ink);
}

/* What happens next, automatically: a note under the list, set apart from its rows. */
.activity__next {
  margin: 6px 0 0;
  padding: var(--s-1) var(--s-2);
  background: var(--paper);
  color: var(--ink-2);
  font-size: 0.75rem;
  line-height: 1.45;
}

/* 10. Flow: Combine, Shape, See, Decide, Act --------------------------------------------------- */

.flow {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  grid-template-rows: auto auto;
  column-gap: var(--s-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.flow__step {
  display: grid;
  grid-row: span 2;
  grid-template-rows: subgrid;
  row-gap: var(--s-5);
  min-width: 0;
}

.flow__visual {
  position: relative;
  grid-row: 1;
  min-height: 232px;
  padding: var(--s-4);
  border: 1px solid var(--rule);
  background: var(--surface);
  font-size: 0.8125rem;
  transition: opacity 240ms ease, border-color 240ms ease;
}

/* The connector to the previous step: a dashed line through the gap. */
.flow__step + .flow__step .flow__visual::before {
  content: "";
  position: absolute;
  top: 50%;
  left: calc(-1 * var(--s-5) - 1px);
  width: var(--s-5);
  border-top: 1px dashed var(--rule-strong);
}

.flow__step + .flow__step .flow__visual::after {
  content: "";
  position: absolute;
  top: calc(50% - 3px);
  left: -6px;
  border: 3px solid transparent;
  border-left: 4px solid var(--rule-strong);
}

.flow__text {
  grid-row: 2;
}

.flow__num {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
}

.flow__title {
  margin: var(--s-1) 0 var(--s-2);
  font-size: 1.25rem;
  letter-spacing: -0.02em;
}

/* When site.js makes the title a button it must still look like a heading. */
.flow__pick {
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-align: left;
  cursor: pointer;
}

.flow__text p:last-child {
  color: var(--ink-2);
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* Small drawn parts inside the flow and module views. */

.sources,
.acts,
.queue,
.audit__checks {
  display: grid;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.sources li,
.queue li {
  display: flex;
  justify-content: space-between;
  gap: var(--s-2);
  padding: 6px var(--s-2);
  border: var(--hairline);
  background: var(--surface);
}

.sources li span:last-child,
.queue li span:last-child {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  line-height: 1.9;
  text-transform: uppercase;
  white-space: nowrap;
}

.pipe {
  display: grid;
  gap: 14px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.pipe li {
  position: relative;
  display: grid;
  gap: 2px;
  padding: 6px var(--s-2);
  border: 1px solid var(--rule);
  border-left: 2px solid var(--ink-2);
}

.pipe li + li::before {
  content: "";
  position: absolute;
  left: 16px;
  top: -15px;
  height: 14px;
  border-left: 1px dashed var(--rule-strong);
}

.pipe code {
  overflow: hidden;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pipe__kind,
.draft__kind {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.pipe__out {
  background: var(--ink);
  color: var(--surface);
}

.pipe .pipe__out {
  border-color: var(--ink);
}

.pipe__out .pipe__kind {
  color: #b9bcbf;
}

.object__title,
.audit__title {
  display: flex;
  justify-content: space-between;
  gap: var(--s-2);
  font-weight: 600;
}

.object__title span,
.audit__title span {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 400;
}

.object__spark {
  display: block;
  width: 100%;
  height: 48px;
  margin: var(--s-3) 0;
  border-bottom: var(--hairline);
}

.object__spark polyline,
.feeds polyline {
  fill: none;
  stroke: var(--ink-2);
  stroke-width: 1.25;
  vector-effect: non-scaling-stroke;
}

.object__rows,
.rule__rows {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0 var(--s-3);
  margin: 0;
}

.object__rows dt,
.object__rows dd,
.rule__rows dt,
.rule__rows dd {
  margin: 0;
  padding: 5px 0;
  border-top: var(--hairline);
}

.object__rows dt,
.rule__rows dt {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  line-height: 1.9;
  text-transform: uppercase;
}

.rule__mode {
  display: grid;
  grid-template-columns: 1fr 1fr;
  margin-top: var(--s-3);
  border: 1px solid var(--ink);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.rule__mode span {
  padding: 6px;
  text-align: center;
}

.rule__mode .is-on {
  background: var(--accent);
  color: var(--ink);
  font-weight: 500;
}

/* Who decides, as a list of three with the chosen one marked (the home page's flow). */
.rule__choice {
  margin: var(--s-3) 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--ink);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.rule__choice li {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 4px 0;
  border-bottom: var(--hairline);
  color: var(--ink-3);
}

.rule__choice li::before {
  content: "";
  width: 8px;
  height: 8px;
  border: 1px solid var(--ink-2);
}

.rule__choice .is-on {
  color: var(--ink);
  font-weight: 500;
}

.rule__choice .is-on::before {
  border-color: var(--ink);
  background: var(--accent);
}

.acts li {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 6px var(--s-2);
  border: var(--hairline);
}

.acts li::before {
  content: "";
  flex: none;
  width: 8px;
  height: 4px;
  margin-top: -3px;
  border-left: 1.5px solid var(--ink);
  border-bottom: 1.5px solid var(--ink);
  transform: rotate(-45deg);
}

.acts__log {
  margin-top: var(--s-3);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* 11. Modules ---------------------------------------------------------------------------------- */

.modules {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: var(--hairline);
  border-left: var(--hairline);
}

.module {
  min-width: 0;
  padding: var(--s-5);
  border-right: var(--hairline);
  border-bottom: var(--hairline);
}

.module--wide {
  grid-column: span 2;
}

.module__view {
  position: relative;
  height: 228px;
  margin-bottom: var(--s-5);
  padding: var(--s-4);
  overflow: hidden;
  border: var(--hairline);
  background: var(--paper);
  font-size: 0.8125rem;
}

.module__view--map {
  padding: 0;
}

.module__view--map .map {
  height: 100%;
  aspect-ratio: auto;
}

.module h3 {
  font-size: 1.0625rem;
  letter-spacing: -0.01em;
}

.module > p {
  margin-top: var(--s-1);
  color: var(--ink-2);
  font-size: 0.9375rem;
}

.feeds {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  border: var(--hairline);
}

.feeds th {
  padding: 6px var(--s-3);
  border-bottom: var(--hairline);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-align: left;
  text-transform: uppercase;
}

.feeds td {
  padding: 7px var(--s-3);
  border-bottom: var(--hairline);
}

.feeds td:nth-child(2) {
  color: var(--ink-3);
}

.feeds td:last-child,
.feeds th:last-child {
  font-family: var(--font-mono);
  text-align: right;
}

.feeds svg {
  display: block;
  width: 72px;
  height: 14px;
}

.feeds .is-attention td:first-child {
  box-shadow: inset 2px 0 0 var(--accent);
}

.feeds .is-attention td:last-child {
  color: var(--accent-ink);
  font-weight: 500;
}

.feeds .is-attention polyline {
  stroke: var(--accent);
}

.audit {
  padding: var(--s-3);
  border: var(--hairline);
  background: var(--surface);
}

.audit__checks {
  margin: var(--s-3) 0;
}

.audit__checks li {
  display: flex;
  justify-content: space-between;
  padding-top: 5px;
  border-top: var(--hairline);
}

.audit__checks li::after {
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  line-height: 1.9;
}

.audit__checks .is-pass::after {
  content: "PASS";
  color: var(--ink-3);
}

.audit__checks .is-fail::after {
  content: "FINDING";
  color: var(--accent-ink);
  font-weight: 500;
}

.audit__task {
  padding: 5px var(--s-2);
  background: var(--sunken);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
}

.draft {
  display: grid;
  gap: var(--s-2);
}

.draft__prompt {
  justify-self: end;
  max-width: 88%;
  padding: var(--s-2) var(--s-3);
  background: var(--ink);
  color: var(--surface);
}

.draft__reply {
  display: grid;
  gap: 2px;
  max-width: 88%;
  padding: var(--s-2) var(--s-3);
  border: var(--hairline);
  background: var(--surface);
}

.draft__chips {
  display: flex;
  gap: var(--s-2);
}

.draft__chips span {
  padding: 3px var(--s-2);
  border: 1px solid var(--ink);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.queue .is-attention {
  border-left: 2px solid var(--accent);
}

.queue .is-attention span:last-child {
  color: var(--accent-ink);
  font-weight: 500;
}

/* The zoomed map in the "Assets and map" module: the frame is three times the view, centred
   between Rotterdam and Hamburg. */
.map--mini .map__frame {
  left: -103%;
  top: -132%;
  width: 300%;
}

/* 12. Split bands and fact lists -------------------------------------------------------------- */

.split {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--s-7);
  align-items: start;
}

.split .band__head {
  margin-bottom: 0;
}

.split__link {
  color: var(--ink);
  text-underline-offset: 4px;
}

.facts {
  margin: 0;
  border-top: 1px solid var(--ink);
}

.facts div {
  display: grid;
  grid-template-columns: 160px minmax(0, 1fr);
  gap: var(--s-4);
  padding: var(--s-4) 0;
  border-bottom: var(--hairline);
}

.facts dt {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: var(--step-label);
  letter-spacing: 0.08em;
  line-height: 2;
  text-transform: uppercase;
}

.facts dd {
  margin: 0;
  font-size: 1.0625rem;
}

/* 13. Closing call to action ------------------------------------------------------------------- */

.closing {
  padding: 112px 0;
  background: var(--ink);
  color: var(--surface);
}

.closing__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: end;
  justify-content: space-between;
  gap: var(--s-6);
}

.closing h2 {
  max-width: 14ch;
}

.closing h2::before {
  content: "";
  display: block;
  width: 10px;
  height: 10px;
  margin-bottom: var(--s-5);
  background: var(--accent);
}

.closing__actions {
  margin-top: 0;
}

.button--light {
  border-color: var(--surface);
  background: var(--surface);
  color: var(--ink);
}

.button--light:hover {
  background: var(--sunken);
}

.closing__email {
  color: #c9cbce;
}

.closing a:focus-visible {
  outline-color: var(--surface);
}

/* 14. Page heads ------------------------------------------------------------------------------- */

.page-head {
  padding: var(--s-5) 0 var(--s-7);
}

.crumbs ol {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  margin: 0 0 var(--s-7);
  padding: 0;
  list-style: none;
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.crumbs li + li::before {
  content: "/";
  margin-right: var(--s-2);
  color: var(--rule-strong);
}

.crumbs a {
  color: inherit;
  text-decoration: none;
}

.crumbs a:hover {
  color: var(--ink);
  text-decoration: underline;
}

.crumbs [aria-current] {
  color: var(--ink);
}

.page-head__copy {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: var(--s-4) var(--s-7);
  align-items: end;
}

.page-head h1 {
  font-size: clamp(2.5rem, 1.5rem + 3vw, 4rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.04em;
}

.page-head__lead {
  color: var(--ink-2);
  font-size: 1.125rem;
  line-height: 1.5;
}

.page-head .button-row,
.page-head .ops {
  margin-top: var(--s-6);
}

/* Links to the sections of a long page (platform), under its head. */
.jump ol {
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--s-6);
  margin: var(--s-7) 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--ink);
}

.jump a {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 44px;
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
}

.jump a:hover {
  text-decoration: underline;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 5px;
}

.jump span {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.08em;
}

/* 15. Switcher: one figure, several views ------------------------------------------------------ */

/* Without the script the views sit side by side in a row that scrolls sideways, and each tab is
   a link that scrolls its view into place. With the script (.is-live) the views share one grid
   cell and the tabs are buttons. Both layouts are as tall as the tallest view, so nothing below
   the figure moves when the script takes over or a tab is pressed. */

.switch {
  min-width: 0;
  border: 1px solid var(--rule);
  background: var(--surface);
}

.switch__tabs {
  display: flex;
  flex-wrap: wrap;
  margin: 0;
  padding: 0;
  list-style: none;
  border-bottom: var(--hairline);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.switch__tab {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 var(--s-4);
  border: 0;
  border-right: var(--hairline);
  background: none;
  color: var(--ink-2);
  font: inherit;
  letter-spacing: inherit;
  text-decoration: none;
  text-transform: inherit;
  cursor: pointer;
}

.switch__tab:hover {
  background: var(--paper);
  color: var(--ink);
}

.switch__tab:focus-visible {
  outline-offset: -2px;
}

/* Tabs that are the steps of a pipeline: an arrow leads into each step after the first. */
.switch__tabs--pipe li + li .switch__tab::before {
  content: "\2192";
  margin-right: var(--s-3);
  color: var(--rule-strong);
}

.switch__views {
  display: flex;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.view {
  display: grid;
  flex: 0 0 100%;
  align-content: start;
  gap: var(--s-4);
  min-width: 0;
  padding: var(--s-5);
  font-size: 0.875rem;
  scroll-margin-top: 96px;
  scroll-snap-align: start;
}

.view__title {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  line-height: 1.4;
  text-transform: uppercase;
}

.view__note {
  max-width: 56ch;
  color: var(--ink-2);
}

.switch__caption {
  padding: var(--s-2) var(--s-5);
  border-top: var(--hairline);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
}

/* Drawn parts used inside views (see also the small parts in section 10). */

/* What comes in, and the objects it becomes. */
.feedin {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  gap: var(--s-5);
  align-items: center;
}

.becomes {
  position: relative;
  display: grid;
  gap: 6px;
  justify-items: start;
  padding-left: var(--s-6);
}

/* The arrow from the sources to the objects. */
.becomes::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: var(--s-5);
  border-top: 1px dashed var(--rule-strong);
}

.becomes::after {
  content: "";
  position: absolute;
  top: calc(50% - 3px);
  left: var(--s-5);
  border: 3px solid transparent;
  border-left: 4px solid var(--rule-strong);
}

.becomes span {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.becomes b {
  padding: 5px var(--s-3);
  background: var(--ink);
  color: var(--surface);
  font-weight: 500;
}

.code {
  margin: 0;
  padding: var(--s-4);
  overflow-x: auto;
  background: var(--ink);
  color: #e9e9e6;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  line-height: 1.8;
}

.code code {
  font-size: inherit;
}

/* A plain card: a record, a task, an alert. */
.card {
  max-width: 460px;
  padding: var(--s-3) var(--s-4);
  border: var(--hairline);
  border-left: 2px solid var(--ink);
}

.card--attention {
  border-left-color: var(--accent);
}

.object .tiles {
  margin-top: var(--s-3);
}

.card .object__rows,
.card .rule__rows {
  margin-top: var(--s-3);
}

.card > dl:first-child {
  margin-top: 0;
}

.card > dl:first-child > :nth-child(-n + 2) {
  border-top: 0;
}

/* Who decides: the rule, AI, or a person. */
.rule__mode--three {
  grid-template-columns: repeat(3, 1fr);
}

/* A second choice under the first (how far the AI may go): marked in ink, so the card keeps
   one accent. */
.rule__mode--sub {
  margin-top: var(--s-2);
  border-color: var(--rule-strong);
}

.rule__mode--sub .is-on {
  background: var(--ink);
  color: var(--surface);
}

/* A risk briefing: the event, what it means, and what of yours it touches. */
.brief {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-5);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.875rem;
  line-height: 1.45;
}

.brief li {
  position: relative;
  display: grid;
  align-content: start;
  gap: var(--s-1);
  padding: var(--s-3);
  border: var(--hairline);
  border-top: 2px solid var(--ink);
  background: var(--surface);
}

.brief li + li::before {
  content: "";
  position: absolute;
  top: 50%;
  left: calc(-1 * var(--s-5));
  width: calc(var(--s-5) - 5px);
  border-top: 1px dashed var(--rule-strong);
}

.brief li + li::after {
  content: "";
  position: absolute;
  top: calc(50% - 3px);
  left: -6px;
  border: 3px solid transparent;
  border-left: 4px solid var(--rule-strong);
}

.brief__kind {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.brief .is-attention {
  border-top-color: var(--accent);
}

.brief-figure {
  margin-top: var(--s-6);
}

.brief-figure__lead {
  max-width: 62ch;
  margin-bottom: var(--s-4);
  color: var(--ink-2);
}

.view__map {
  height: 300px;
  border: var(--hairline);
}

.view__map .map {
  height: 100%;
}

/* A cropped map: the box shows part of the frame, enlarged --zoom times and centred on the point
   (--cx, --cy), given as fractions of the frame. cqw and cqh are the box's own size. */
.map--crop {
  container-type: size;
  aspect-ratio: auto;
  height: 100%;
}

.map--crop .map__frame {
  width: calc(var(--zoom) * 100cqw);
  left: calc(50cqw - var(--cx) * var(--zoom) * 100cqw);
  top: calc(50cqh - var(--cy) * var(--zoom) * 100cqw * 8 / 11);
}

.map--crop .map__route:not(#route-sea-esb-hum),
.map--crop .map__leader {
  display: none;
}

/* The North Sea, with the storm warning and the lane it threatens. */
.map--crop-storm {
  --zoom: 1.9;
  --cx: 0.43;
  --cy: 0.4;
}

/* The southern North Sea coast, from Rotterdam to Hamburg. */
.map--crop-coast {
  --zoom: 3;
  --cx: 0.51;
  --cy: 0.545;
}

.tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-3);
  margin: 0;
}

.tiles div {
  padding: var(--s-3);
  border: var(--hairline);
}

.tiles dt {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.tiles dd {
  margin: var(--s-1) 0 0;
  font-size: 1.75rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.1;
}

.tiles .is-attention {
  border-left: 2px solid var(--accent);
}

.bars {
  display: block;
  width: 100%;
  height: 96px;
  border-bottom: 1px solid var(--ink-2);
}

.bars rect {
  fill: var(--ink-2);
}

.bars .is-attention {
  fill: var(--accent);
}

.versions {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--ink);
}

.versions li {
  display: grid;
  grid-template-columns: 44px 92px minmax(0, 1fr);
  gap: var(--s-3);
  padding: var(--s-2) 0;
  border-bottom: var(--hairline);
}

.versions b {
  font-family: var(--font-mono);
  font-weight: 500;
}

.versions time,
.versions small {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  line-height: 1.9;
}

.versions small {
  display: block;
}

/* 16. Platform stages -------------------------------------------------------------------------- */

.stage {
  scroll-margin-top: var(--s-4);
}

.stage__grid {
  display: grid;
  grid-template-columns: minmax(0, 4fr) minmax(0, 8fr);
  gap: var(--s-7);
  align-items: start;
}

.stage__num {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: var(--step-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.stage h2 {
  margin: var(--s-2) 0 var(--s-4);
}

.stage__lead {
  color: var(--ink-2);
}

.stage__points {
  margin: var(--s-5) 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--ink);
  font-size: 0.9375rem;
}

.stage__points li {
  padding: var(--s-3) 0;
  border-bottom: var(--hairline);
}

/* 17. Use cases and scenario chains ------------------------------------------------------------ */

/* Cards reuse the module grid (section 11). A chain reads top to bottom: what was seen, the rule
   it met, who decided, what was done. */

/* These are paragraphs inside a module, so they need the module's own specificity to keep their
   look (see ".module > p" in section 11). */
.module > .label {
  display: flex;
  margin-top: 0;
  color: var(--ink-3);
  font-size: var(--step-label);
}

/* A card's title when it is an h2 (the band's own h2 style is for section headings). */
.module .module__title {
  margin-top: var(--s-1);
  font-size: 1.375rem;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

.module > .module__more {
  margin-top: var(--s-4);
}

.module > .module__num {
  margin-top: 0;
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
}

.module__num + h3 {
  margin-top: var(--s-2);
}

.chain {
  margin: var(--s-4) 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.9375rem;
  line-height: 1.4;
}

.chain li {
  position: relative;
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  gap: var(--s-2);
  padding: 7px 0 7px var(--s-5);
  border-top: var(--hairline);
}

/* The node, and the line that joins it to its neighbours. */
.chain li::before {
  content: "";
  position: absolute;
  z-index: 1;
  top: 13px;
  left: 0;
  width: 9px;
  height: 9px;
  border: 1.5px solid var(--ink);
  background: var(--surface);
}

.chain li::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  left: 4px;
  border-left: 1px dashed var(--rule-strong);
}

.chain li:first-child::after {
  top: 13px;
}

.chain li:last-child::after {
  bottom: auto;
  height: 13px;
}

.chain__kind {
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  line-height: 2.1;
  text-transform: uppercase;
}

/* A decision a person takes is the accent; one the system takes is solid ink. */
.chain .is-held::before {
  border-color: var(--ink);
  background: var(--accent);
}

.chain .is-auto::before,
.chain li:last-child::before {
  background: var(--ink);
}

.chain li:last-child::before {
  border-radius: 50%;
}

.module--dark {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  gap: var(--s-5);
  background: var(--ink);
  color: var(--surface);
}

.module--dark .module__title {
  max-width: 22ch;
  font-size: 1.75rem;
  letter-spacing: -0.03em;
  line-height: 1.1;
}

.module--dark > p {
  color: #c9cbce;
}

.module--dark a:focus-visible {
  outline-color: var(--surface);
}

/* Small drawn views inside the use-case cards. */

.rating {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  margin-top: var(--s-3);
  border: 1px solid var(--ink);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  text-align: center;
}

.rating span {
  padding: 6px 0;
}

.rating span + span {
  border-left: var(--hairline);
}

.rating .is-on {
  background: var(--accent);
  color: var(--ink);
  font-weight: 500;
}

.rating .is-was {
  background: var(--sunken);
}

.modules--five {
  grid-template-columns: repeat(5, minmax(0, 1fr));
}

/* The map symbol for a risk input, drawn at the top of its card: the cards double as the map's
   legend. */
.glyph {
  position: relative;
  display: block;
  width: 28px;
  height: 28px;
  margin-bottom: var(--s-4);
}

.glyph::before {
  content: "";
  position: absolute;
  inset: 0;
  box-sizing: border-box;
}

.glyph--weather::before {
  border: 1px dashed var(--ink-2);
  border-radius: 50% 44% 52% 46%;
  background: repeating-linear-gradient(135deg, transparent 0 3px, rgb(18 19 22 / 0.18) 3px 4px);
}

.glyph--advisory::before {
  border: 1px dashed var(--accent);
  border-radius: 50%;
  background: rgb(238 90 31 / 0.1);
}

.glyph--incident::before {
  inset: 4px 2px 2px;
  background: var(--ink);
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

.glyph--rating::before {
  inset: 3px;
  border: 1.5px solid var(--ink);
  background: var(--surface);
}

.glyph--rating::after {
  content: "B";
  position: absolute;
  inset: 0;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 28px;
  text-align: center;
}

.glyph--travel::before {
  border: 1px solid var(--ink-2);
  border-radius: 50%;
  background: var(--surface);
}

.glyph--travel::after {
  content: "5";
  position: absolute;
  inset: 0;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 28px;
  text-align: center;
}

/* Risk console: more kinds of pin, and a calm weather cell (the accent belongs to the advisory
   the decision is about). */

.pin--incident::before {
  left: -6px;
  top: -7px;
  width: 12px;
  height: 11px;
  border: 0;
  background: var(--ink);
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}

/* The incident that needs attention (it also carries the ping). */
.pin--incident.pin--attention::before {
  left: -7px;
  top: -8px;
  width: 14px;
  height: 13px;
  background: var(--accent);
}

.ops.is-held .pin--incident.pin--attention::before {
  left: -6px;
  top: -7px;
  width: 12px;
  height: 11px;
}

.pin--rated::before {
  left: -8px;
  top: -8px;
  width: 16px;
  height: 16px;
}

.pin--rated .pin__count {
  font-size: 0.625rem;
}

.pin--rated .pin__label {
  left: 12px;
}

.pin--rated.pin--label-left .pin__label {
  left: auto;
  right: 12px;
}

.pin--advisory::before {
  left: -34px;
  top: -34px;
  width: 68px;
  height: 68px;
  border: 1px dashed var(--accent);
  border-radius: 50%;
  background: rgb(238 90 31 / 0.1);
}

.pin--advisory .pin__label {
  left: 0;
  top: -52px;
  transform: translateX(-50%);
  border: 1px solid var(--accent);
  background: var(--surface);
  color: var(--ink);
  font-weight: 500;
}

/* The whole advisory area can be picked; the travellers' ring at its centre sits on top. */
.pin--advisory .pin__hit {
  left: -34px;
  top: -34px;
  width: 68px;
  height: 68px;
  padding: 0;
}

.map--calm .map__route,
.map--calm .map__leader {
  display: none;
}

.map--calm .map__zone-glow {
  fill: rgb(18 19 22 / 0.07);
}

.map--calm .map__zone-edge,
.map--calm .map__zone-contour {
  stroke: var(--ink-3);
}

.map--calm .map__zone-contour--1 {
  fill: rgb(18 19 22 / 0.04);
}

.map--calm .map__zone-hatch {
  fill: rgb(18 19 22 / 0.32);
}

.map--calm .map__zone-track {
  stroke: var(--ink-2);
}

.map--calm .map__zone-arrow {
  fill: var(--ink-2);
}

.map--calm .map__zone-tag {
  border-color: var(--rule-strong);
}

.map--calm .map__zone-tag b {
  background: var(--sunken);
}

.map--calm .map__zone-time {
  color: var(--ink-2);
}

/* Field operations console (risk management): the console over the map of the central Sahel.
   Sizes on the map are true to its scale: the frame is 1540 km wide (tools/sahel_map.py). */

/* The risk areas (generic examples) and their name tags. Each area has its own muted colour,
   as a soft tint, a dashed outline and a hatch; the hatches (patterns in the generated overlay)
   also differ in density and direction, so the two areas stay apart without colour. */
.map__area--high {
  --area: var(--zone-high);
}

.map__area--restricted {
  --area: var(--zone-restricted);
}

.map__area-tint {
  fill: var(--area);
  fill-opacity: 0.09;
}

.map__area-edge {
  stroke: var(--area);
  stroke-width: 1;
  stroke-dasharray: 3 3;
  vector-effect: non-scaling-stroke;
}

.map__area-hatch--high {
  fill: var(--zone-high);
  fill-opacity: 0.3;
}

.map__area-hatch--restricted {
  fill: var(--zone-restricted);
  fill-opacity: 0.24;
}

.map__tag {
  padding: 0 6px;
  border: 1px solid var(--area);
  background: var(--surface);
  color: var(--area);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  line-height: 16px;
  text-transform: uppercase;
  white-space: nowrap;
  transform: translate(-50%, -50%);
}

.map__tag--high {
  --area: var(--zone-high);
}

.map__tag--restricted {
  --area: var(--zone-restricted);
}

/* 50 km around the event: 100 km across, of the frame's 1540 km. Its accent tint sits on a
   veil of white, so the ring reads on top of the tinted, hatched risk area beneath it. */
.ring50 {
  width: calc(100% * 100 / 1540);
  aspect-ratio: 1;
  border: 1px dashed var(--accent);
  border-radius: 50%;
  background:
    linear-gradient(rgb(238 90 31 / 0.14), rgb(238 90 31 / 0.14)),
    rgb(255 255 255 / 0.6);
  transform: translate(-50%, -50%);
}

/* Once the decision is made the ring goes quiet; the number still awaited keeps the accent. */
.ops.is-held .ring50 {
  border-color: var(--ink-2);
  background: rgb(255 255 255 / 0.6);
}

/* How many of the people inside the ring have answered, above it. */
.map__count {
  display: inline-flex;
  gap: var(--s-2);
  margin-top: calc(-100% * 50 / 1540 - 8px);
  padding: 1px 2px 1px 6px;
  border: 1px solid var(--ink-2);
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  letter-spacing: 0.08em;
  line-height: 16px;
  text-transform: uppercase;
  white-space: nowrap;
  transform: translate(-50%, -100%);
}

.map__count b {
  padding: 0 5px;
  background: var(--accent);
  font-weight: 500;
}

/* A site's staff: a count above its mark. */
.pin__staff {
  position: absolute;
  left: -9px;
  top: -24px;
  box-sizing: border-box;
  min-width: 18px;
  height: 16px;
  padding: 0 3px;
  border: 1px solid var(--ink-2);
  border-radius: 8px;
  background: rgb(255 255 255 / 0.92);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: 500;
  line-height: 14px;
  text-align: center;
}

/* Below the marker, where the badge above would run into a neighbour's label. */
.pin__staff--below {
  top: 8px;
}

/* The site an event affects: the site's square, outlined in the accent. Quieter than the event
   itself, which has the filled mark and the ping. */
.pin--affected::before {
  border: 2px solid var(--accent);
}

.pin--affected .pin__label {
  color: var(--ink);
  font-weight: 500;
}

.ops.is-held .pin--affected::before {
  border: 1.5px solid var(--ink);
}

/* A callout that hangs above its anchor: the leader meets its bottom edge. */
.manifest--above {
  transform: translate(calc(-100% + 16px), -100%);
}

.map--sahel {
  background: var(--surface);
}

.map--sahel .map__scale {
  width: 12.99%; /* 200 km of the 1540 km frame */
}

/* 18. Tenant drawing (security) ---------------------------------------------------------------- */

/* Three tenants side by side; above them, one request at a time (the switcher's views) aimed at
   a tenant's column: who signs in where, and where data is kept. */

.tenants {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-4);
  margin: 0;
  padding: 0 var(--s-5) var(--s-5);
  list-style: none;
}

.tenant {
  display: grid;
  gap: 6px;
  padding: var(--s-3);
  border: 1px solid var(--rule);
  color: var(--ink-3);
  font-size: 0.8125rem;
}

.tenant--yours {
  border: 1.5px solid var(--ink);
  color: var(--ink);
}

.tenant__name {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.tenant__cell {
  padding: 6px var(--s-2);
  border: var(--hairline);
  background: var(--paper);
}

.tenant--yours .tenant__cell {
  border-color: var(--rule-strong);
  background: var(--surface);
}

.view--request {
  padding-bottom: 0;
}

.request {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-4);
}

.request p {
  margin: 0;
}

.request__path {
  position: relative;
  display: grid;
  justify-items: center;
  gap: var(--s-2);
  grid-column: 2;
  padding-bottom: 44px;
  text-align: center;
}

.request__path--other {
  grid-column: 3;
}

/* The arrow down into the tenant. */
.request__path::before {
  content: "";
  position: absolute;
  bottom: 6px;
  left: 50%;
  height: 34px;
  border-left: 1px dashed var(--ink-2);
}

.request__path::after {
  content: "";
  position: absolute;
  bottom: 0;
  left: calc(50% - 4px);
  border: 4px solid transparent;
  border-top: 6px solid var(--ink-2);
  border-bottom: 0;
}

.request__chip {
  padding: 4px var(--s-3);
  border: 1px solid var(--ink);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
}

.request__result {
  padding: 3px var(--s-3);
  background: var(--ink);
  color: var(--surface);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.request .view__note {
  grid-column: 1;
  grid-row: 1;
  align-self: start;
}

/* 19. FAQ and text pages ----------------------------------------------------------------------- */

.faq-group + .faq-group {
  margin-top: var(--s-8);
}

.faq-group h2 {
  font-size: var(--step-h2);
  letter-spacing: -0.025em;
  line-height: 1.1;
}

.faq {
  border-top: 1px solid var(--ink);
}

.faq details {
  border-bottom: var(--hairline);
}

.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  min-height: 56px;
  padding: var(--s-3) 0;
  font-weight: 500;
  list-style: none;
  cursor: pointer;
}

.faq summary::-webkit-details-marker {
  display: none;
}

.faq summary::after {
  content: "+";
  flex: none;
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: 1.125rem;
  font-weight: 400;
}

.faq details[open] summary::after {
  content: "\2212";
  color: var(--accent-ink);
}

.faq__answer {
  max-width: 62ch;
  padding: 0 var(--s-6) var(--s-5) 0;
  color: var(--ink-2);
}

/* Numbered hints (contact). */
.hints {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--ink);
  counter-reset: hint;
}

.hints li {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr);
  padding: var(--s-4) 0;
  border-bottom: var(--hairline);
  counter-increment: hint;
}

.hints li::before {
  content: "0" counter(hint);
  color: var(--ink-3);
  font-family: var(--font-mono);
  font-size: var(--step-label);
  letter-spacing: 0.08em;
  line-height: 2.2;
}

.hints strong {
  display: block;
}

.hints span {
  color: var(--ink-2);
  font-size: 0.9375rem;
}

.email-big {
  display: inline-block;
  font-size: clamp(1.5rem, 1rem + 2.2vw, 2.5rem);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.2;
  text-decoration-color: var(--accent);
  text-decoration-thickness: 2px;
  text-underline-offset: 8px;
}

.band--tight {
  padding: var(--s-8) 0;
}

.error-page {
  padding: var(--s-8) 0 var(--s-9);
}

.error-page .label {
  margin-bottom: var(--s-4);
}

/* 20. States set by site.js -------------------------------------------------------------------- */

/* A closed callout and its leader. On phones the callout is a strip under the map and stays. */
@media (min-width: 641px) {
  .manifest.is-closed,
  .map__leader.is-closed {
    visibility: hidden;
  }
}

/* A live switcher: every view in one grid cell, only the chosen one visible. */
.switch.is-live .switch__views {
  display: grid;
  overflow: visible;
}

.switch.is-live .view {
  grid-area: 1 / 1;
  visibility: hidden;
}

.switch.is-live .view.is-shown {
  visibility: visible;
}

.switch__tab[aria-pressed="true"],
.switch__tab[aria-pressed="true"]:hover {
  background: var(--ink);
  color: var(--surface);
}

/* Replay: parts of the story not yet reached are hidden without moving anything else. */
.ops [data-stage].is-pending {
  visibility: hidden;
}

/* Before the warning arrives there is no zone; before the rule fires (and after the hold is
   approved) the route and the shipment are drawn like any other. */
.ops.is-pending-zone .map__zone {
  opacity: 0;
}

.ops.is-pending-rule #route-sea-esb-hum,
.ops.is-held #route-sea-esb-hum {
  stroke: var(--ink-2);
  stroke-width: 1.25;
}

.ops.is-pending-rule .pin--attention::before,
.ops.is-held .pin--attention::before {
  left: -5px;
  top: -5px;
  width: 10px;
  height: 10px;
  background: var(--ink);
}

.ops.is-pending-rule .pin--attention::after,
.ops.is-held .pin--attention::after {
  display: none;
}

/* Layers switched off. */
.map.is-hidden-sites [data-layer="sites"],
.map.is-hidden-vehicles [data-layer="vehicles"],
.map.is-hidden-vehicles .map__route--road,
.map.is-hidden-travellers [data-layer="travellers"],
.map.is-hidden-staff [data-layer="staff"],
.map.is-hidden-convoys [data-layer="convoys"],
.map.is-hidden-convoys .map__route--road,
.map.is-hidden-flights [data-layer="flights"],
.map.is-hidden-flights .map__route--air,
.map.is-hidden-flights .map__leader,
.map.is-hidden-vessels [data-layer="vessels"],
.map.is-hidden-vessels .map__route--sea,
.map.is-hidden-destinations [data-layer="destinations"],
.map.is-hidden-high [data-layer="high"],
.map.is-hidden-high .map__area--high,
.map.is-hidden-restricted [data-layer="restricted"],
.map.is-hidden-restricted .map__area--restricted,
.map.is-hidden-zones .map__zone,
.map.is-hidden-zones .map__zone-tag,
.map.is-hidden-zones .map__zone-time,
.map.is-hidden-advisories [data-layer="advisories"],
.map.is-hidden-incidents [data-layer="incidents"],
.map.is-hidden-ratings [data-layer="ratings"] {
  visibility: hidden;
}

/* Once the advisory has been acted on it is drawn like any other. */
.ops.is-held .pin--advisory::before {
  border-color: var(--ink-3);
  background: rgb(18 19 22 / 0.05);
}

.ops.is-held .pin--advisory .pin__label {
  border-color: var(--rule-strong);
}

/* The flow while one step is highlighted. */
.flow.is-live .flow__step:not(.is-active) .flow__visual {
  opacity: 0.5;
}

.flow.is-live .flow__step.is-active .flow__visual {
  border-color: var(--ink);
}

.flow.is-live .flow__step.is-active .flow__num {
  color: var(--accent-ink);
}

.flow__pick:hover,
.flow__step.is-active .flow__pick {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--accent);
  text-underline-offset: 5px;
}

/* 21. Motion (only when the reader has not asked for less) ------------------------------------- */

@media (prefers-reduced-motion: no-preference) {
  .ops [data-stage] {
    transition: opacity 400ms ease;
  }

  .ops [data-stage].is-pending {
    opacity: 0;
  }

  .map__zone,
  #route-sea-esb-hum {
    transition: opacity 600ms ease, stroke 400ms ease;
  }

  /* The cell breathes: its inner bands swell and fade in turn, slowly. */
  .map__zone-contour,
  .map__zone-core {
    animation: zone-breathe 5s ease-in-out infinite;
  }

  .map__zone-contour--1 {
    animation-delay: -1.6s;
  }

  .map__zone-core {
    animation-delay: 0.8s;
  }

  .pin--attention::after {
    animation: pin-pulse 2.4s ease-out infinite;
  }

  .map__route--sea {
    animation: route-flow 1.6s linear infinite;
  }
}

@keyframes pin-pulse {
  0% {
    transform: scale(0.45);
    opacity: 1;
  }

  100% {
    transform: scale(1.6);
    opacity: 0;
  }
}

@keyframes zone-breathe {
  50% {
    opacity: 0.45;
  }
}

@keyframes route-flow {
  to {
    stroke-dashoffset: -18;
  }
}

/* 22. Narrow screens --------------------------------------------------------------------------- */

@media (max-width: 1180px) {
  /* The rail moves under the map: inspector and decision side by side, activity below. */
  .ops__body {
    grid-template-columns: minmax(0, 1fr);
  }

  .ops__rail {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-template-rows: auto auto;
    border-left: 0;
    border-top: var(--hairline);
  }

  .ops__rail .inspect {
    border-right: var(--hairline);
  }

  .ops__rail .activity {
    grid-column: 1 / -1;
    border-top: var(--hairline);
  }

  .flow {
    column-gap: var(--s-4);
  }

  .flow__step + .flow__step .flow__visual::before {
    left: calc(-1 * var(--s-4) - 1px);
    width: var(--s-4);
  }
}

@media (max-width: 960px) {
  .intro__copy,
  .page-head__copy,
  .band__head--split,
  .split,
  .stage__grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .stage__grid,
  .split {
    gap: var(--s-6);
  }

  .modules--five {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .intro__copy {
    gap: var(--s-4);
  }

  /* The flow runs top to bottom: drawing on the left, words on the right. */
  .flow {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: none;
    row-gap: var(--s-6);
  }

  .flow__step {
    grid-row: auto;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: auto;
    column-gap: var(--s-5);
    align-items: center;
  }

  .flow__visual,
  .flow__text {
    grid-row: 1;
  }

  .flow__visual {
    min-height: 0;
  }

  .flow__step + .flow__step .flow__visual::before {
    top: calc(-1 * var(--s-6) - 1px);
    left: 50%;
    width: 0;
    height: var(--s-6);
    border-top: 0;
    border-left: 1px dashed var(--rule-strong);
  }

  .flow__step + .flow__step .flow__visual::after {
    top: -7px;
    left: calc(50% - 3px);
    border: 3px solid transparent;
    border-top: 4px solid var(--rule-strong);
  }

  .modules {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .intro {
    padding: var(--s-7) 0 var(--s-6);
  }

  .intro__copy {
    margin-bottom: var(--s-6);
  }

  .band,
  .closing {
    padding: var(--s-8) 0;
  }

  .band__head {
    margin-bottom: var(--s-6);
  }

  .ops__crumbs span:first-child,
  .ops__crumbs span + span::before {
    display: none;
  }

  .ops__live {
    display: none;
  }

  /* A taller map on phones: the frame is enlarged (152% wide) and centred on the North Sea, so
     the scene keeps its size while labels and pins keep theirs. The frame sets the box's height
     and the layer switches follow it, under the map rather than over it. */
  .ops .map {
    aspect-ratio: auto;
  }

  .ops .map__frame {
    position: relative;
    left: -14%;
    width: 152%;
  }

  /* Fewer labels: countries, ticks, the scale, traveller and offshore names, and names that would
     clip at the edge or cover a neighbour (pin--edge) give way to the scene. */
  .map__place--country,
  .map__tick,
  .map__scale,
  .pin--offshore .pin__label,
  .pin--travellers .pin__label,
  .pin--edge .pin__label {
    display: none;
  }

  /* The warning keeps its amber chip; its name and the track's time give way. */
  .map__zone-tag span,
  .map__zone-time {
    display: none;
  }

  .map__zone-tag {
    padding: 1px;
  }

  .map__layers {
    position: static;
    display: flex;
    align-items: center;
    gap: var(--s-3);
    padding: 2px var(--s-3);
    border-width: 1px 0 0;
  }

  .map__layers-title {
    display: none;
  }

  .map__layers ul {
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--s-4);
  }

  /* Larger touch targets for the console's controls. */
  .layer {
    min-height: 40px;
  }

  .ask__button {
    min-height: 44px;
  }

  .pin__hit {
    left: -20px;
    top: -20px;
    width: 40px;
    height: 40px;
    padding: 4px;
  }

  /* The flight manifest leaves the map: a strip under it, above the layer switches. The frame
     makes room (the strip's height) and the leader line is dropped. */
  .map--callout .map__frame {
    margin-bottom: 136px;
  }

  .ops .map .manifest {
    top: 100%;
    left: 9.21%;   /* the frame is 152% wide and starts 14% to the left: 14 / 152 */
    width: 65.79%; /* 100 / 152 */
    height: 136px;
    padding-top: var(--s-1);
    border-width: 1px 0 0;
    border-color: var(--rule);
    transform: none;
  }

  .map__leader {
    display: none;
  }

  .brief {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-4);
  }

  .brief li + li::before {
    top: calc(-1 * var(--s-4));
    left: var(--s-4);
    width: 0;
    height: var(--s-4);
    border-top: 0;
    border-left: 1px dashed var(--rule-strong);
  }

  .brief li + li::after {
    display: none;
  }

  /* The Sahel map on phones: enlarged (160% wide) and centred on the event area, with the far
     north cropped. Its callout strip follows the same frame (46 / 160 and 100 / 160). */
  .ops .map--sahel .map__frame {
    left: -46%;
    width: 160%;
    margin-top: -12%;
  }

  .ops .map--sahel .manifest {
    left: 28.75%;
    width: 62.5%;
    height: 158px;
  }

  .map--sahel.map--callout .map__frame {
    margin-bottom: 158px;
  }

  /* Only the number still awaited stays on the map; the rest is in the inspector. */
  .map__count span {
    display: none;
  }

  .map__count {
    padding: 1px;
  }


  /* The advisory's name moves under its ring, clear of the pins to the north. */
  .pin--advisory .pin__label {
    top: 38px;
  }

  .ops__rail {
    grid-template-columns: minmax(0, 1fr);
  }

  .ops__rail .inspect {
    border-right: 0;
  }

  /* On phones the flow is a row of cards to swipe through, the next one peeking in. */
  .flow {
    display: flex;
    gap: var(--s-4);
    margin: 0 calc(-1 * var(--gutter));
    padding: 0 var(--gutter) var(--s-3);
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-padding: 0 var(--gutter);
    scroll-snap-type: x mandatory;
  }

  .flow__step {
    flex: 0 0 80%;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    row-gap: var(--s-4);
    scroll-snap-align: start;
  }

  .flow__visual {
    grid-row: 1;
    min-height: 236px;
  }

  .flow__text {
    grid-row: 2;
  }

  .flow__step + .flow__step .flow__visual::before,
  .flow__step + .flow__step .flow__visual::after {
    display: none;
  }

  .modules,
  .modules--five {
    grid-template-columns: minmax(0, 1fr);
  }

  .module--wide {
    grid-column: auto;
  }

  .page-head {
    padding-bottom: var(--s-6);
  }

  .crumbs ol {
    margin-bottom: var(--s-6);
  }

  .jump ol {
    margin-top: var(--s-6);
  }

  .view {
    padding: var(--s-4);
  }

  .switch__tab {
    padding: 0 var(--s-3);
  }

  .feedin {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-4);
  }

  /* The arrow to the objects points down instead of across. */
  .becomes {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    padding: var(--s-4) 0 0;
  }

  .becomes::before {
    top: 0;
    left: var(--s-4);
    width: 0;
    height: var(--s-3);
    border-top: 0;
    border-left: 1px dashed var(--rule-strong);
  }

  .becomes::after {
    display: none;
  }

  .view__map {
    height: 260px;
  }

  .tiles dd {
    font-size: 1.375rem;
  }

  .versions li {
    grid-template-columns: 36px minmax(0, 1fr);
  }

  .versions time {
    display: none;
  }

  .tenants {
    gap: var(--s-2);
    padding: 0 var(--s-4) var(--s-4);
  }

  .tenant {
    padding: var(--s-2);
    font-size: 0.75rem;
  }

  .tenant__cell {
    padding: 4px;
  }

  .request {
    gap: var(--s-2);
  }

  /* The explanation moves above the request, across the full width, so the arrow still ends
     on the tenants. */
  .request .view__note {
    grid-column: 1 / -1;
    grid-row: 1;
  }

  .request__path {
    grid-row: 2;
  }

  .request__path--own {
    grid-column: 1 / -1;
  }

  /* Aimed at the third tenant: the request sits to the right and its arrow comes down over the
     middle of that column (a sixth of the width from the right edge). */
  .request__path--other {
    grid-column: 1 / -1;
    justify-items: end;
  }

  .request__path--other::before {
    right: 16.6%;
    left: auto;
  }

  .request__path--other::after {
    right: calc(16.6% - 4px);
    left: auto;
  }

  .faq__answer {
    padding-right: 0;
  }

  .module--dark .module__title {
    font-size: 1.5rem;
  }

  .feeds th:nth-child(2),
  .feeds td:nth-child(2) {
    display: none;
  }

  .facts div {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-1);
  }
}

/* Touch screens: every control in the drawn views gets a 44 px target (design language,
   "Controls"). Mouse users keep the denser desktop sizes. */
@media (pointer: coarse) {
  .layer,
  .ask__button,
  .flow__pick {
    min-height: 44px;
  }

  .pin__hit {
    left: -22px;
    top: -22px;
    width: 44px;
    height: 44px;
    padding: 6px;
  }
}

/* 23. Base breakpoints and print --------------------------------------------------------------- */

@media (max-width: 720px) {
  /* The navigation moves to its own row under the brand and the call to action. */
  .site-header__inner {
    flex-wrap: wrap;
    gap: 0 var(--s-4);
    padding-top: var(--s-2);
  }

  .site-nav {
    order: 3;
    flex-basis: 100%;
  }

  .site-header__cta {
    min-height: 44px;
  }
}

@media (max-width: 480px) {
  :root {
    --gutter: 16px;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    transition: none !important;
    animation: none !important;
  }
}

@media print {
  .site-header,
  .site-footer,
  .skip-link {
    display: none;
  }

  body {
    background: #fff;
  }
}
