/*
 * The website view (#site, "Ohne Fahren entdecken"): the whole screen as a
 * site of its own, its header, its pages and their foot. It builds on
 * world.css (the sections it shares with the driving panel, the dark tokens)
 * and is loaded right after it. Everything here is scoped to the view: the
 * panel shows the same sections and does not change with it.
 *
 * One grid, one scale, a few type steps: every edge lies on one of three
 * lines (A: the first column, B: the second half, C: the right edge), every
 * space comes from the rhythm tokens, every text size from a step. Spaces are
 * measured from a baseline to a cap height: large type is trimmed to its
 * caps and its baseline with negative margins (from the fonts' metrics), and
 * a space is always a padding or a margin-top of the block, never the trim.
 */

/* ---------- the grid and the rhythm ---------- */

.site {
  /* the grid: columns, the margin at the screen's edge and the gutter between columns, by width (below) */
  --site-max: 1280px;
  --cols: 4;
  --margin: 20px;
  --gutter: 16px;
  /* the scroll bar's width (ui/site.mjs measures it): its room is kept on the page's right, the header takes it off its own edge */
  --sbw: 0px;
  /* the page's edge: the margin, or wider where the screen is wider than the page – the same for the header, the page and its foot */
  --edge: max(var(--margin), (100vw - var(--sbw) - var(--site-max)) / 2);
  /* the spacing scale */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 24px;
  --s-6: 32px;
  --s-7: 40px;
  --s-8: 48px;
  --s-9: 64px;
  --s-10: 80px;
  --s-11: 96px;
  --s-12: 128px;
  --s-13: 160px;
  /* the rhythm: the header's height; the header to the title's caps; the title's baseline to the lead's caps; the lead to the first block;
     between blocks; inside a block; a row's padding; the last block to the end of the page; the end of the page to the foot */
  --head-h: 56px;
  --page-top: var(--s-7);
  --title-gap: 20px;
  --intro-gap: var(--s-8);
  --block-gap: var(--s-9);
  --group-gap: var(--s-5);
  --row-y: 20px;
  --end-gap: var(--s-11);
  --foot-gap: var(--s-9);
  /* the type steps (sizes): display (a page's title), title (a project, the next page), heading, lead; running text */
  --display: clamp(40px, 26px + 4.375vw, 96px);
  --title: clamp(28px, 22px + 1.875vw, 48px);
  --heading: clamp(20px, 17.5px + 0.78vw, 28px);
  --lead: clamp(19px, 17.5px + 0.47vw, 24px);
  --body: 16px;
  --body-line: 24px;
}
@media (min-width: 480px) {
  .site {
    --margin: 32px;
  }
}
@media (min-width: 768px) {
  .site {
    --cols: 8;
    --margin: 40px;
    --gutter: 24px;
    --head-h: 64px;
    --page-top: var(--s-9);
    --title-gap: var(--s-5);
    --intro-gap: var(--s-9);
    --block-gap: var(--s-10);
    --row-y: var(--s-5);
    --end-gap: 112px;
    --foot-gap: var(--s-10);
    --body: 17px;
    --body-line: 28px;
  }
}
@media (min-width: 1024px) {
  .site {
    --cols: 12;
    --margin: 48px;
    --page-top: var(--s-10);
    --title-gap: 28px;
    --intro-gap: var(--s-10);
    --block-gap: var(--s-11);
    --group-gap: var(--s-6);
    --end-gap: var(--s-12);
    --foot-gap: var(--s-11);
  }
}
@media (min-width: 1280px) {
  .site {
    --margin: 64px;
    --gutter: 32px;
    --page-top: var(--s-11);
    --title-gap: var(--s-6);
    --intro-gap: var(--s-11);
    --block-gap: var(--s-12);
    --row-y: 28px;
    --end-gap: var(--s-13);
  }
}
/* short: a phone held sideways – its own, tighter rhythm, the grid by width */
@media (max-height: 540px) and (orientation: landscape) {
  .site {
    --margin: var(--s-5);
    --head-h: 52px;
    --page-top: var(--s-5);
    --title-gap: var(--s-3);
    --intro-gap: var(--s-6);
    --block-gap: var(--s-8);
    --group-gap: var(--s-4);
    --row-y: var(--s-4);
    --end-gap: var(--s-9);
    --foot-gap: var(--s-8);
    --display: 40px;
    --title: 28px;
  }
}

/* ---------- the surface: the whole screen, a header and the page under it that scrolls with its foot at the end ---------- */

.site {
  position: fixed;
  inset: 0;
  width: 100vw;
  height: 100dvh;
  margin: 0;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  overflow: hidden;
  color: var(--ink);
  background: var(--page);
}
.site:not([open]) {
  display: none;
}
.site::backdrop {
  background: transparent;
}
/*
 * opening and closing (ui/site.mjs): the view is clipped to what it grows out
 * of, and meanwhile its white is two layers of its own, the view and its
 * header having no background: over what opened it (its rect, --from-inset
 * and --from-radius) a layer that fades in over the intro's words (::before),
 * and everywhere else one that stands (::after, its spread shadow), so the
 * surface sweeping over the world is white from its first frame. The first
 * reaches a pixel under the second, so their two rounded edges never fall on
 * the same pixels (a seam). The header's hairline fades with the header's
 * items.
 */
.site:is([data-arriving], [data-leaving])::before,
.site:is([data-arriving], [data-leaving])::after {
  content: "";
  position: fixed;
  inset: var(--from-inset, 0px);
  z-index: -1;
  border-radius: var(--from-radius, 0px);
  pointer-events: none;
}
.site:is([data-arriving], [data-leaving])::before {
  margin: -1px;
  background: var(--page);
}
.site:is([data-arriving], [data-leaving])::after {
  box-shadow: 0 0 0 200vmax var(--page);
}
.site:is([data-arriving], [data-leaving]),
.site:is([data-arriving], [data-leaving]) .site-head {
  background: transparent;
}
.site[data-leaving] .site-head::before {
  opacity: 0;
  transition-duration: var(--dur-exit);
}

/* ---------- the header: the logo on line A, the pages over the page's centre, the actions on line C ---------- */

.site-head {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  column-gap: var(--s-2);
  height: calc(var(--head-h) + var(--safe-top));
  /* (its box the page's: the scroll bar's room taken off its right) */
  padding: var(--safe-top) calc(var(--edge) + var(--sbw) + var(--safe-right)) 0 calc(var(--edge) + var(--safe-left));
  background: var(--page);
}
/* the page has scrolled under it: a hairline fades in (under the mark of the current page) */
.site-head::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: var(--line);
  opacity: 0;
  transition: opacity var(--dur-fade) var(--ease-out);
}
.site.scrolled .site-head::before {
  opacity: 1;
}
.site-logo {
  justify-self: start;
  display: flex;
}
/* (the mark has more air below than above: a pixel down, it stands in the middle) */
.site-logo img {
  width: auto;
  height: 24px;
  translate: 0 1px;
  mix-blend-mode: multiply;
}
.site-nav {
  grid-column: 2;
  position: relative;
  align-self: stretch;
  display: flex;
  align-items: center;
}
.site-nav a {
  padding: 10px 12px;
  border-radius: 8px;
  color: var(--muted);
  font: 700 15px/20px Satoshi, system-ui, sans-serif;
  letter-spacing: -0.01em;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--dur-tint) var(--ease-out) var(--lit-after, 0ms);
}
/* (1080 to 1279: a little closer, so the six fit between the logo and the actions in both languages) */
@media (min-width: 1080px) and (max-width: 1279px) {
  .site-nav a {
    padding-inline: 9px;
  }
}
@media (hover: hover) {
  .site-nav a:hover {
    color: var(--ink);
  }
}
.site-nav a[aria-current] {
  color: var(--ink);
}
/* (as the current page moves, the new one lights a moment later: the old one dims, the mark travels, the new one lights – ui/site.mjs sets .passing until the swap) */
.site-nav.passing a[aria-current] {
  --lit-after: 120ms;
}
/* the current page's mark: under its link's text on the header's edge, travelling from link to link (ui/site.mjs sets --x and --w, and moves it) */
.site-nav-mark {
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 1px;
  height: 2px;
  background: var(--blue);
  transform-origin: 0 0;
  transform: translateX(var(--x, 0)) scaleX(var(--w, 0));
}
.site-actions {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: var(--s-2);
}
.site-menu,
.site-close {
  width: 44px;
  height: 44px;
  box-shadow: none;
  background: transparent;
}
.site-menu {
  display: none;
}
/* the last symbol's glyph on line C (a 22 px symbol in a 44 px target: 11 px of air) */
.site-close,
.site-menu:has(+ .site-close[hidden]) {
  margin-inline-end: -11px;
}
@media (hover: hover) {
  .site-menu:hover,
  .site-close:hover {
    background: var(--hover);
  }
}
/*
 * the menu button's three lines turn into a cross while the sheet is open:
 * the outer two meet in the middle, then turn (the middle one goes at once);
 * back, they turn straight first, then part, and the middle one returns
 */
.site-menu path {
  transform-box: fill-box;
  transform-origin: center;
  transition:
    rotate 160ms var(--ease-in-out),
    translate 200ms var(--ease-out) 100ms,
    scale 160ms var(--ease-out) 120ms,
    opacity 160ms var(--ease-out) 120ms;
}
.site-menu[aria-expanded="true"] path {
  transition:
    translate 160ms var(--ease-in-out),
    rotate 240ms var(--ease-out) 120ms,
    scale 120ms var(--ease-in),
    opacity 120ms var(--ease-in);
}
.site-menu[aria-expanded="true"] path:nth-child(1) {
  translate: 0 5px;
  rotate: 45deg;
}
.site-menu[aria-expanded="true"] path:nth-child(2) {
  scale: 0 1;
  opacity: 0;
}
.site-menu[aria-expanded="true"] path:nth-child(3) {
  translate: 0 -5px;
  rotate: -45deg;
}
/* under the sheet the page steps back behind a veil of its own colour, which takes the click beside the sheet (ui/site.mjs closes it then) */
.site-scrim {
  position: absolute;
  inset: calc(var(--head-h) + var(--safe-top)) 0 0;
  z-index: 1;
  background: var(--page);
  opacity: 0;
  pointer-events: none;
  transition: opacity 280ms var(--ease-out);
}
.site:has(.site-nav.open) .site-scrim {
  opacity: 0.75;
  pointer-events: auto;
}
/* (a page picked in the sheet leaves under the veil: it stays until the new page is there, then fades over it – ui/site.mjs .veiled) */
.site.veiled .site-scrim {
  opacity: 0.75;
}

/* ---------- the page: on the grid, its large type trimmed to caps and baseline ---------- */

.site-body {
  display: flex;
  flex-direction: column;
  overflow-x: clip;
  overflow-y: auto;
  overscroll-behavior: contain;
  /* (the scroll bar's room on one side only: the page and its foot keep the header's edges, the foot's hairline runs to the bar) */
  scrollbar-gutter: stable;
  font-kerning: normal;
  text-rendering: optimizeLegibility;
}
.site-body:focus-visible {
  outline-offset: -4px;
}
/* (a page on its way out takes no clicks; what has the focus keeps it, the new page's heading takes it at the swap: ui/site.mjs) */
.site-body .sections > section.leaving {
  pointer-events: none;
}
.site-top {
  flex: none;
  height: 1px;
  margin-bottom: -1px;
}
.site-page {
  flex: 1 0 auto;
  padding: var(--page-top) calc(var(--edge) + var(--safe-right)) 0 calc(var(--edge) + var(--safe-left));
}
.site-body .sections {
  max-width: var(--site-max);
  margin: 0 auto;
}
/* every page is the grid; its parts span it unless the page says otherwise, the space between them comes from the rhythm alone */
.site-body .sections > section:not([hidden]) {
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  column-gap: var(--gutter);
  row-gap: 0;
}
.site-body :where(.sections > section > *) {
  grid-column: 1 / -1;
  margin: 0;
}
/* rows that keep the page's columns (subgrid; where there is none, the same columns of their own, which match: they have no padding at the sides) */
.site-body :is(.project, .service-list, .service-list > li, .regions, .regions > li) {
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  grid-template-columns: subgrid;
  column-gap: var(--gutter);
  row-gap: 0;
}
.site-body :where(.project, .service-list, .service-list > li, .regions, .regions > li) > * {
  grid-column: 1 / -1;
}
/* a page shows from its top, also when the address names its section (#kontakt) and the browser jumps to it */
.site[open] .sections > section {
  scroll-margin-top: 100vh;
}
/* without the 3D world the website view is the site: one quiet line says why */
.site-note {
  max-width: var(--site-max);
  margin: 0 auto var(--intro-gap);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--line);
}
/* in the website view the foot holds the legal links: the contact section's own are for the panel */
.site .sections .legal {
  display: none;
}

/*
 * The hairlines: on top of a block (::before), and below the last row of a
 * list (::after, on the first pixel after it, where the next row's line
 * would be: so it is also the line of whatever lies beside it there). Drawn
 * as a border, which forced colours keep.
 */
.site-body :is(.cards li, .site-plan-caption, .project, .project .facts li, .service-list > li, .person, .sections > section > .facts li, .contact-row, .brief, details, .figures li, .regions > li),
.site-page .onward {
  position: relative;
  border: 0;
}
.site-body :is(.cards li, .site-plan-caption, .project, .project .facts li, .service-list > li, .person, .sections > section > .facts li, .contact-row, .brief, details, .figures li, .regions > li)::before,
.site-body :is(.cards li:last-child, .service-list > li:last-child, .regions > li:last-child, details:last-of-type, .person)::after,
.site-body .project .facts li:last-child::after,
.site-body .sections > section > .facts li:last-child::after,
.site-page .onward::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  border-top: 1px solid var(--line);
  pointer-events: none;
}
.site-body :is(.cards li:last-child, .service-list > li:last-child, .regions > li:last-child, details:last-of-type, .person)::after,
.site-body .project .facts li:last-child::after,
.site-body .sections > section > .facts li:last-child::after {
  inset: auto 0 -1px;
}

/*
 * The type. Large type is trimmed to its cap height and its baseline, with
 * negative margins from the fonts' metrics: the baseline stands
 * (L − (ascent + descent)) / 2 + ascent under the top of a line (L: the line
 * height), Satoshi's ascent 1.010 em, its descent 0.240, its caps 0.734;
 * Source's 0.984, 0.273 and 0.656. Browsers lay a line out on whole pixels
 * (the ascent and the descent rounded, the half-leading rounded down), and
 * where CSS can round, the trim does it alike, so caps and baselines land
 * on their lines to the pixel at every size. Titles from the title step up
 * stand on line A by the ink of their first letter (ui/optical.mjs sets
 * --hang).
 */
.site {
  --satoshi-base: calc((1lh - 1.25em) / 2 + 1.01em);
  --source-base: calc((1lh - 1.257em) / 2 + 0.984em);
}
@supports (width: round(down, 1.5px, 1px)) {
  .site {
    --satoshi-base: calc(round(1.01em, 1px) + round(down, (1lh - round(1.01em, 1px) - round(0.24em, 1px)) / 2, 1px));
    --source-base: calc(round(0.984em, 1px) + round(down, (1lh - round(0.984em, 1px) - round(0.273em, 1px)) / 2, 1px));
  }
}
.site-body :is(.sections > section > h2, .project h3, .onward-next, .cards b, .service-list h3, .region-name, .sections > section > h3, .contact-mail, summary, .figures b) {
  margin-block: calc(0.734em - var(--satoshi-base)) calc(var(--satoshi-base) - 1lh);
}
.site-body .sections .lead {
  margin-block: calc(0.656em - var(--source-base)) calc(var(--source-base) - 1lh);
}
.site-body :is(h2, h3, .onward-next, summary) {
  text-wrap: balance;
  hyphens: manual;
}
.site-body :is(p, .lead, li, dd) {
  text-wrap: pretty;
}
/* display: a page's title */
.site-body .sections > section > h2 {
  max-inline-size: 13em;
  font-size: var(--display);
  line-height: 0.96;
  letter-spacing: max(-0.05em, -0.03em - 0.12vw);
}
/* title: a project's name, the next page */
.site-body :is(.project h3, .onward-next) {
  max-inline-size: 16em;
  font: 700 var(--title) / 1.04 Satoshi, system-ui, sans-serif;
  letter-spacing: -0.035em;
}
.site-body :is(.sections > section > h2, .project h3, .onward-next, .figures b) {
  margin-inline-start: calc(var(--hang, 0) * 1em);
}
/* heading: the index's titles, a service, a strength, a continent, "Standorte", the address (the questions: below) */
.site-body :is(.cards b, .service-list h3, .sections > section > .facts li, .region-name, .sections > section > h3, .contact-mail) {
  max-inline-size: 22em;
  font: 700 var(--heading) / 1.15 Satoshi, system-ui, sans-serif;
  letter-spacing: -0.025em;
  color: var(--ink);
}
/* lead: one sentence under a title (its caps the title gap under the title's baseline) */
.site-body .sections > section > h2 + .lead {
  padding-top: var(--title-gap);
}
/* (one sentence, set in even lines: no word left alone at its end, no phrase torn at the last moment) */
.site-body .sections .lead {
  max-inline-size: 28em;
  text-wrap: balance;
  font-size: var(--lead);
  line-height: 1.4;
  letter-spacing: -0.005em;
  color: var(--ink);
}
/* body: running text, in ink at a reading measure */
.site-body :is(.sections > section > p:not(.lead, .form-note, .process), .project > p:not(.lead, .form-note), .service-list p, details p, .cities) {
  max-inline-size: 36em;
  font-size: var(--body);
  line-height: var(--body-line);
  color: var(--ink);
}
/* meta: what goes with the text, muted */
.site-body :is(.meta, .cards a > span:not(.arrow), .site-plan-caption, .network-map figcaption, .region-name b, .sections .form-note, .figures li > span, .person span, .field-count, .brief-keys),
.site-note,
.site-foot {
  font: 400 14px/20px Source, system-ui, sans-serif;
  letter-spacing: 0.005em;
  color: var(--muted);
}
.site-body :is(.meta, .cards a > span:not(.arrow), .network-map figcaption, .sections .form-note, .figures li > span, .person span) {
  max-inline-size: 40em;
}
/* label: buttons and the form's labels */
.site .button {
  line-height: 20px;
  letter-spacing: -0.01em;
}
.site-body .brief label {
  font: 700 15px/20px Satoshi, system-ui, sans-serif;
  letter-spacing: -0.01em;
}

/* ---------- start: the title over the whole width, the lead and the pages as an index beside the 3D world from above ---------- */

.site-body .sections > section > .site-plan {
  margin-top: var(--intro-gap);
}
.site-body .sections > section > .cards {
  margin-top: var(--intro-gap);
}
.site-body .sections > section > .site-plan:not([hidden]) + .cards {
  margin-top: var(--block-gap);
}
.cards {
  margin: 0;
  padding: 0;
  list-style: none;
}
.cards li {
  display: grid;
}
.cards a {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 20px;
  align-content: center;
  column-gap: var(--s-4);
  padding-block: var(--row-y);
  color: var(--ink);
  text-decoration: none;
}
/* (focused: the ring a little off the row's lines) */
.cards a:focus-visible {
  outline-offset: 4px;
}
.cards b,
.cards a > span:not(.arrow) {
  grid-column: 1;
  transition:
    color var(--dur-tint) var(--ease-out),
    translate 280ms var(--ease-out);
}
.cards a > span:not(.arrow) {
  margin-top: var(--s-2);
}
.cards .arrow {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: center;
  justify-self: end;
  font-size: 20px;
  line-height: 1;
  color: var(--muted);
  transition: color var(--dur-tint) var(--ease-out);
}
/* the blue line along its hairline (the line grammar, below) */
.cards a::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 1px;
  background: var(--blue);
}
/*
 * pointed at, focused, or its ring on the plan (.lit): the title turns blue
 * and leans in, the description after it, the line draws and the arrow
 * passes through; back, they lean out at once, a little faster. Clicked, it
 * stays so while its page leaves (.chosen, ui/site.mjs), and its arrow
 * leaves the way it points.
 */
@media (hover: hover) {
  .site-body .cards a:is(:hover, :focus-visible, .lit, .chosen) :is(b, .arrow) {
    color: var(--blue);
  }
  .site[data-motion="full"] .cards a:is(:hover, :focus-visible, .lit, .chosen) > :is(b, span:not(.arrow)) {
    translate: var(--nudge) 0;
    transition:
      color var(--dur-tint) var(--ease-out),
      translate var(--dur-hover) var(--ease-out);
  }
  .site[data-motion="full"] .cards a:is(:hover, :focus-visible, .lit, .chosen) > span:not(.arrow) {
    transition-delay: 0ms, 40ms;
  }
}

/* the plan: the ground drawn once (ui/siteplan.mjs), the rings and names over it, its caption under a hairline */
.site-plan {
  margin: 0;
}
.site-plan-map {
  position: relative;
  aspect-ratio: 1;
}
.site-plan-map canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
/* (the rings and names over it: the start screen's names layer, only the rings take the pointer) */
.site-plan-marks {
  pointer-events: none;
}
.site-plan-ring {
  display: grid;
  place-items: center;
  pointer-events: auto;
  transition: scale var(--dur-fade) var(--ease-out), background-color var(--dur-fade) var(--ease-out);
}
.site-plan-ring .place-check {
  width: 58%;
  height: 58%;
  stroke: #fff;
  opacity: 0;
}
.site-plan-ring.visited {
  background: var(--blue);
}
.site-plan-ring.visited .place-check {
  opacity: 1;
}
/* lit (its row pointed at, or the ring): larger, its name in the blue – as the way there arrives (ui/siteplan.mjs sets --arrive); back without waiting */
.site-plan-ring.lit {
  scale: 1.18;
  transition: scale 280ms var(--ease-out), background-color var(--dur-fade) var(--ease-out);
}
.site[data-motion="full"] .site-plan-ring.lit,
.site[data-motion="full"] .site-plan-label.lit b {
  transition-delay: max(0ms, calc(var(--arrive, 80ms) - 80ms));
}
/* (on a weak device a ring lit is simply larger: no motion) */
.site[data-motion="low"] .site-plan-ring {
  transition: background-color var(--dur-fade) var(--ease-out);
}
/* (pressed: at once, whether or not the way has arrived) */
.site[data-motion] .site-plan-ring:active {
  scale: var(--press-icon);
  transition: scale var(--dur-press) var(--ease-out) 0s;
}
.site-plan-ring.challenge {
  background: rgba(255, 255, 255, 0.7);
  box-shadow: inset 0 0 0 1.5px rgba(31, 102, 220, 0.6);
}
.site-plan-label b {
  transition: color var(--dur-tint) var(--ease-out);
}
.site-plan-label.lit b {
  color: var(--blue);
}
.site-plan-label span span {
  font-size: 14px;
}
/* (where it would cover the ground beside the name, the distance goes under it, on the ring's side) */
.site-plan-label.stacked > span {
  flex-direction: column;
  align-items: flex-start;
  gap: 0;
}
.site-plan-label.stacked[data-align="end"] > span {
  align-items: flex-end;
}
.site-plan-label.stacked[data-align="center"] > span {
  align-items: center;
}
.site-plan-label.stacked span span {
  line-height: 18px;
}
/* (a small plan has no distances: there a name too long for its room breaks onto two lines instead) */
.site-plan-marks.compact .site-plan-label.stacked b {
  width: min-content;
  white-space: normal;
}
.site-plan-marks.compact .site-plan-label.stacked[data-align="end"] b {
  text-align: right;
}
.site-plan-marks.compact .site-plan-label.stacked[data-align="center"] b {
  text-align: center;
}
/* (the challenge's name a word a line: its portal stands at the edge of the world) */
.site-plan-label.challenge > span {
  white-space: normal;
}
.site-plan-label.challenge b {
  width: min-content;
  font-size: 14px;
  line-height: 1.2;
  color: var(--muted);
}
/* where the website starts: a dot of ink, ringed by the page */
.site-plan-start {
  position: absolute;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--ink);
  box-shadow: 0 0 0 2px var(--page);
}
/* the way to the place pointed at, by road from the start dot to the edge of its ring (ui/siteplan.mjs draws it in) */
.site-plan-route {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.site-plan-route path {
  fill: none;
  stroke: var(--blue);
  stroke-width: 3;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1 2;
}
.site-plan-caption {
  padding-top: var(--s-3);
}

/* ---------- the projects: each a spread, its words beside a large picture ---------- */

.site-body .sections > section > .project {
  margin-top: var(--block-gap);
  padding-top: var(--s-7);
}
.site-body .sections > section > .project:first-of-type {
  margin-top: var(--intro-gap);
}
.site-body .project-head {
  display: grid;
  justify-items: start;
  align-items: start;
  gap: 0;
}
.site-body .project-head .meta {
  margin-top: var(--s-3);
}
.site-body .status-dot {
  width: 6px;
  height: 6px;
}
.site-body .project > .lead {
  padding-top: var(--s-5);
}
.site-body .project > p:not(.lead, .form-note) {
  margin-top: var(--s-4);
}
.site-body .project > :is(.facts, .button, .form-note) {
  margin-top: var(--group-gap);
}
.site-body .project > .button {
  justify-self: start;
}
/* the facts: rows, each with its line on top */
.site-body .project .facts {
  display: grid;
  gap: 0;
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.005em;
  color: var(--ink);
}
.site-body .project .facts li {
  padding-block: 10px;
  white-space: normal;
}
.site-body .facts li::after {
  content: none;
}

/* ---------- the services: names and their text on the grid, the way of working as a line over four steps ---------- */

.site-body .service-list {
  margin-top: var(--intro-gap);
  padding: 0;
  border: 0;
}
.site-body .service-list > li {
  align-items: first baseline;
  padding-block: var(--row-y);
}
.site-body .service-list p {
  margin-top: var(--s-2);
}
.site-body .process {
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: var(--gutter);
  margin-top: var(--block-gap);
  padding-top: var(--s-5);
  font: 700 var(--heading) / 1.15 Satoshi, system-ui, sans-serif;
  letter-spacing: -0.025em;
  color: var(--ink);
}
.site-body .process::before,
.site-body .process::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
}
.site-body .process::after {
  height: 2px;
  top: -0.5px;
  background: var(--blue);
  transform-origin: left;
}
.site-body .process span + span::before {
  content: none;
}
.site-body .sections > section > .button {
  margin-top: calc(2 * var(--group-gap));
}

/* ---------- about: the lead, the person between hairlines, the strengths side by side ---------- */

/* the person: the picture, the name with the flag right after it, the role under it */
.site-body .person {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  align-items: center;
  gap: 0;
  margin-top: var(--s-6);
  padding-block: var(--s-5);
}
.site-body .person > div {
  display: contents;
}
.site-body .person img {
  grid-row: 1 / span 2;
  width: 64px;
  height: 64px;
  margin-inline-end: var(--s-4);
}
.site-body .person strong {
  grid-column: 2;
  grid-row: 1;
  align-self: end;
  font: 700 20px/1.15 Satoshi, system-ui, sans-serif;
  letter-spacing: -0.025em;
}
.site-body .person span {
  grid-column: 2 / -1;
  grid-row: 2;
  align-self: start;
  margin-top: var(--s-1);
}
/* (its middle on the middle of the name's caps) */
.site-body .person .flag {
  grid-column: 3;
  grid-row: 1;
  align-self: end;
  width: 16px;
  height: 16px;
  margin: 0 0 3px var(--s-2);
}
.site-body .sections > section > .person ~ p {
  margin-top: var(--s-6);
}
/* the strengths: each under its own line (its top trimmed in its padding, which lies between the line and the text) */
.site-body .sections > section > .facts {
  display: grid;
  column-gap: var(--gutter);
  margin-top: var(--block-gap);
}
.site-body .sections > section > .facts li {
  max-inline-size: none;
  margin-block: 0 calc(var(--satoshi-base) - 1lh);
  padding: calc(var(--s-4) + 0.734em - var(--satoshi-base)) 0 var(--s-4);
  white-space: normal;
}

/* ---------- contact: the address and the form under the same line, the questions under the address ---------- */

.site-body .contact-row {
  display: grid;
  justify-items: start;
  gap: 0;
  margin-top: var(--intro-gap);
  padding-top: var(--s-6);
}
/* ("Adresse kopieren" a small secondary button, as everywhere in the view) */
.site-body .contact-row .button {
  min-height: 40px;
  margin-top: var(--s-3);
  font-size: 14px;
}
.site-body .brief {
  row-gap: var(--s-5);
  margin-top: var(--block-gap);
  padding-top: var(--s-6);
}
/* (32 px to the first field) */
.site-body .ideas {
  margin-bottom: var(--s-2);
  font-size: var(--body);
  line-height: var(--body-line);
  color: var(--muted);
}
/* (what happens on sending, before it is sent: a meta line) */
.site-body .brief-state[data-state="idle"] .state-text {
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.005em;
}
.site-body .brief input {
  block-size: 48px;
  padding: 0 var(--s-4);
}
.site-body .brief textarea {
  min-block-size: 160px;
  padding: var(--s-3) var(--s-4);
}
.site-body .sections > section > details {
  padding: 0;
}
.site-body .sections > section > details:first-of-type {
  margin-top: var(--s-8);
}
/* a question: its +/− a cross of two bars on the column's edge, on the middle of the first line's caps; open, the upright bar lies down */
.site-body summary {
  position: relative;
  display: block;
  padding-block: var(--s-5);
  padding-inline-end: calc(12px + var(--s-4));
  font: 700 20px/1.15 Satoshi, system-ui, sans-serif;
  letter-spacing: -0.025em;
}
.site-body summary::before,
.site-body summary::after {
  content: "";
  position: absolute;
  right: 0;
  top: calc(var(--s-5) + var(--satoshi-base) - 0.367em - 0.75px);
  width: 12px;
  height: 1.5px;
  background: var(--muted);
}
.site-body summary::after {
  rotate: 90deg;
}
.site-body details[open] > summary::after {
  content: "";
  rotate: 0deg;
}
.site-body details p {
  padding-bottom: var(--s-5);
}

/* ---------- the data centre: large figures, the map, the continents in rows ---------- */

/* the figures: each cell its own size (container units), the numbers and the word on one baseline */
.site-body .figures {
  --figure: clamp(36px, 21cqi, 88px);
  --figure-word: clamp(24px, 13cqi, 56px);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--group-gap) var(--gutter);
  margin-top: var(--intro-gap);
}
.site-body .figures li {
  container-type: inline-size;
  gap: 0;
  padding: var(--s-5) 0 0;
  contain: layout paint;
}
.site-body .figures b {
  font-size: var(--figure);
  line-height: 1;
  letter-spacing: -0.045em;
}
/* (the word as tall as a number's caps, its baseline on theirs) */
.site-body .figures .figure-word b {
  font-size: var(--figure-word);
  line-height: 1;
  margin-top: calc(0.734 * var(--figure) - var(--satoshi-base));
}
.site-body .figures li > span {
  margin-top: var(--s-3);
  /* (a label of three words in two even lines, where its cell is narrow: "Kunden / pro Monat") */
  text-wrap: balance;
}
/* the map straight on the page */
.site-body .network-map {
  margin-top: var(--block-gap);
  padding: 0;
  border: 0;
}
.site-body .network-map figcaption {
  margin-top: var(--s-4);
}
/* "Standorte" and the continents: a row each, the cities flowing after the name */
.site-body .sections > section > h3 {
  padding-top: var(--block-gap);
}
.site-body .regions {
  margin-top: var(--s-5);
}
.site-body .regions > li {
  align-items: first baseline;
  padding-block: var(--row-y);
}
.site-body .region-name {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
}
.site-body .cities {
  margin-top: var(--s-2);
}
.site-body .sections > section > .form-note {
  margin-top: var(--s-5);
}

/* ---------- the end of a page: the next one large, the link and the place in the 3D world on its baseline ---------- */

/*
 * A row that wraps: the next page's title at the left, its actions at line C
 * on the title's baseline where both fit in one line, else under it at line A
 * (and always under it without the way into the world: the start is no place).
 */
.site-page .onward {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: last baseline;
  /* (the actions' reach above their line given back where they wrap) */
  gap: calc(var(--s-4) + 10px) var(--gutter);
  max-width: var(--site-max);
  margin: var(--end-gap) auto 0;
  padding-top: var(--s-6);
}
.onward-next {
  position: relative;
  justify-self: start;
  color: var(--ink);
  text-decoration: none;
}
.onward-next::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -6px;
  height: 2px;
  background: var(--blue);
}
/* (the address's arrow tints in a tint's time too) */
.site-body .contact-mail .arrow {
  transition: color var(--dur-tint) var(--ease-out);
}
/* (its arrow 0.2 em after the space: 0.12 em of margin, then the component's 0.08 em of padding – the rule wins over the component's margin, below) */
.site .onward-next .arrow {
  margin-inline-start: 0.12em;
  color: var(--muted);
  transition: color var(--dur-tint) var(--ease-out);
}
@media (hover: hover) {
  .site .onward-next:is(:hover, :focus-visible, .chosen) .arrow {
    color: var(--blue);
  }
}
.site-page .onward-actions {
  align-items: baseline;
  gap: var(--s-2) var(--s-5);
  /*
   * (the button stands 10 px higher than its 20 px label line: by that much
   * the actions reach above the line they share with the title, so a small
   * title keeps its caps on the onward's padding and only they move to meet
   * its baseline)
   */
  margin-top: -10px;
}
.site-page .onward-actions > * {
  white-space: nowrap;
}
.site-page .onward-share {
  margin-left: 0;
  line-height: 20px;
}
.site-page .onward-actions:not(:has(.button:not([hidden]))) {
  flex-basis: 100%;
}

/*
 * The foot of every page: who, the languages, the legal pages. On phones
 * the legal pages take a line of their own; the languages stand at the
 * right of the first where they fit beside it, else at the start of a line
 * of their own (their text on line A or C either way: their targets reach
 * out beyond it). Every line is as tall as a 32 px target, so the lines
 * stand evenly apart however they wrap.
 */
.site-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--s-2) var(--s-4);
  margin-top: var(--foot-gap);
  /* (its hairline the first pixel of its padding: it never moves, a border is all it needs) */
  padding: calc(var(--s-4) - 1px) calc(var(--edge) + var(--safe-right)) calc(var(--s-4) + var(--safe-bottom)) calc(var(--edge) + var(--safe-left));
  border-top: 1px solid var(--line);
}
.site-foot :is(.languages, .legal) {
  font-size: inherit;
}
.site-foot > span {
  display: flex;
  align-items: center;
  min-block-size: 32px;
}
.site-foot .legal {
  column-gap: var(--s-3);
}
/* (the narrowest phones: closer, so the legal pages still make one line) */
@media (max-width: 359px) {
  .site-foot .legal {
    column-gap: var(--s-2);
  }
}
.site-foot .languages {
  margin-inline: -6px;
}
.site-foot .legal {
  flex-basis: 100%;
  padding: 0;
}

/*
 * ---------- motion states: a page comes in (ui/site.mjs, ui/choreo.mjs) ----------
 *
 * Nothing here moves: every entrance is a Web Animation, which holds what is
 * about to arrive at its start (fill "backwards") – so nothing is hidden
 * without the script, below the level "full", or once it has come in. The
 * hairline of a block is its ::before (above) and draws by its transform.
 */

/*
 * a heading split into its lines for one entrance (ui/motion.mjs splitLines):
 * each line a block where the browser had it, clipped just outside its
 * glyphs – 0.1em above its box (an umlaut's dots), 0.18em below (a "j"), by
 * a clip that reaches past its box, not by padding cancelled with margins,
 * which would collapse between the lines and push each one down. The line
 * rises from its height plus both reaches below (ui/choreo.mjs MASK_FRAMES).
 * The two wrappers take nothing from the rules for the heading's own spans
 * (the arrow of the next page's title).
 */
.site .ln,
.site .ln-in {
  all: unset;
  display: block;
}
.site .ln {
  white-space: nowrap;
  clip-path: inset(-0.1em -0.08em -0.18em);
}
/* a row's text as one box for its entrance, apart from its hairline (ui/motion.mjs wrapContent): laid out as the row's own text was */
.site .unit-in {
  all: unset;
  display: block;
}

/*
 * ---------- micro-interactions: what answers the pointer, the focus and a press ----------
 *
 * Hover lives under (hover: hover); everything that moves also needs the
 * level "full" (at "low" only the colours change, with reduced motion even
 * they change at once: world.css). A focused control shows what a pointer
 * shows, its ring at once (base.css :focus-visible).
 */

/*
 * The line grammar: a line that lights up under a link draws from the left
 * and leaves to the right – the index's rows (.cards a::before, above), the
 * next page (.onward-next::after) and the address (.contact-mail::after). A
 * press shows it whole at once. Below "full" the line is a state, not a
 * movement: it stands there at once (at "low" the hairline turns blue,
 * with the title's colour).
 */
.site-body .cards a::before,
.site-body .contact-mail::after,
.site .onward-next::after {
  transform: scaleX(0);
  transform-origin: right;
  transition: none;
}
.site[data-motion="full"] .cards a::before,
.site[data-motion="full"] .contact-mail::after,
.site[data-motion="full"] .onward-next::after {
  transition: transform var(--dur-hover) var(--ease-in-out);
}
/* (not while its part still comes in: it would draw across the text rising to it – ui/site.mjs data-entering) */
@media (hover: hover) {
  .site-body .cards a:is(:hover, :focus-visible, .lit):not([data-entering] *)::before,
  .site-body .contact-mail:is(:hover, :focus-visible):not([data-entering] *)::after,
  .site .onward-next:is(:hover, :focus-visible):not([data-entering] *)::after,
  .site-body .cards a.chosen::before,
  .site .onward-next.chosen::after {
    transform: scaleX(1);
    transform-origin: left;
  }
}
.site-body .cards a:active::before,
.site-body .contact-mail:active::after,
.site .onward-next:active::after {
  transform: scaleX(1);
  transform-origin: left;
}
.site[data-motion="full"] .cards a:active::before,
.site[data-motion="full"] .contact-mail:active::after,
.site[data-motion="full"] .onward-next:active::after {
  transition-duration: 0s;
}

/*
 * The arrow (→, ↗ .out): it passes through in the way it points – it leaves
 * its box, and its copy (its own text-shadow, no second glyph in the page)
 * comes in from the other side. Its box is one em high, so the copy below
 * a ↗ stays out of sight, and reaches 0.08 em beyond the glyph at the sides,
 * taken back by its margins: the arrow stands where it stood – on the
 * text's baseline, so a heading split into its lines finds it on its line
 * (ui/motion.mjs measureLines reads the tops).
 */
.site .arrow {
  overflow: clip;
  padding: 0 0.08em;
  margin: 0 -0.08em;
  line-height: 1;
}
.site .arrow i {
  display: inline-block;
}
.site[data-motion="full"] .arrow i {
  text-shadow: -1.2em 0 currentColor;
  transition: translate var(--dur-hover) var(--ease-in-out);
}
.site[data-motion="full"] .arrow.out i {
  text-shadow: -1em 1em currentColor;
}
@media (hover: hover) {
  .site[data-motion="full"] :is(a, button):is(:hover, :focus-visible, .lit, .chosen) .arrow i {
    translate: 1.2em 0;
  }
  .site[data-motion="full"] :is(a, button):is(:hover, :focus-visible, .lit, .chosen) .arrow.out i {
    translate: 1em -1em;
  }
}

/*
 * Buttons: their colours change in a tint's time; pressed (at "full") they
 * give a little at once and come back (--press-ms: in at a press's speed,
 * out at a fade's). How a button fades in and out is --button-fade, so a
 * button that fades its own way (the close button beside the sheet) sets
 * only that and keeps the rest, whatever the selectors weigh.
 */
.site :is(.button, .icon-button) {
  --press-ms: var(--dur-fade);
  transition:
    background-color var(--dur-tint) var(--ease-out),
    box-shadow var(--dur-tint) var(--ease-out),
    color var(--dur-tint) var(--ease-out),
    scale var(--press-ms) var(--ease-out),
    var(--button-fade, opacity var(--dur-fade) var(--ease-out));
}
.site[data-motion="full"] .button:active:not(:disabled, [aria-disabled="true"]) {
  --press-ms: var(--dur-press);
  scale: var(--press);
}
.site[data-motion="full"] .icon-button:active {
  --press-ms: var(--dur-press);
  scale: var(--press-icon);
}
/* a link that is a button ("Link kopieren", the ideas): its line turns blue */
.site .text-button {
  transition:
    color var(--dur-tint) var(--ease-out),
    text-decoration-color var(--dur-tint) var(--ease-out);
}
@media (hover: hover) {
  .site .text-button:hover {
    text-decoration-color: var(--blue);
  }
}
/*
 * "Link kopieren" says "Link kopiert ✓" for a moment (ui/clipboard.mjs):
 * the button is always as wide as the wider of the two (a hidden copy of
 * the other label, data-copied, holds the room), so neither its text nor
 * what stands beside it moves. Its text stands on line A where the actions
 * start there (under the next page's title), and next to the button where
 * the two stand on the title's line at line C (768 and up).
 */
.site .text-button[data-copied] {
  display: inline-flex;
  flex-direction: column;
  text-align: start;
}
.site .text-button[data-copied]::after {
  content: attr(data-copied);
  block-size: 0;
  overflow: hidden;
  visibility: hidden;
  white-space: nowrap;
}
@media (min-width: 768px) {
  .site-page .onward-actions:has(.button:not([hidden])) .text-button[data-copied] {
    text-align: end;
  }
}
/* the foot's links: underlined in a quiet line, which turns blue as the text turns ink */
.site-foot :is(.legal a, .languages button:not([aria-pressed="true"])) {
  text-decoration: underline 1px var(--line-strong);
  text-underline-offset: 3px;
  transition:
    color var(--dur-tint) var(--ease-out),
    text-decoration-color var(--dur-tint) var(--ease-out);
}
@media (hover: hover) {
  .site-foot :is(.legal a, .languages button:not([aria-pressed="true"])):hover {
    color: var(--ink);
    text-decoration-color: var(--blue);
  }
}

/*
 * A question opens: its cross turns blue when pointed at, and its upright
 * bar lies down onto the other; the answer unrolls (where the browser can
 * size it, ::details-content) and its text rises into it – or, where it
 * cannot or nothing moves, the answer is there and its text fades in.
 */
.site-body summary::before,
.site-body summary::after {
  transition: background-color var(--dur-tint) var(--ease-out);
}
.site[data-motion="full"] .site-body summary::after {
  transition:
    background-color var(--dur-tint) var(--ease-out),
    rotate 280ms var(--ease-in-out);
}
@media (hover: hover) {
  .site-body summary:is(:hover, :focus-visible)::before,
  .site-body summary:is(:hover, :focus-visible)::after {
    background: var(--blue);
  }
}
.site {
  interpolate-size: allow-keywords;
}
.site-body details[open] > :not(summary) {
  animation: site-answer-fade var(--dur-fade) var(--ease-out) backwards;
}
@supports selector(::details-content) {
  .site-body details::details-content {
    block-size: 0;
    overflow: clip;
  }
  .site-body details[open]::details-content {
    block-size: auto;
  }
  .site[data-motion="full"] .site-body details::details-content {
    transition:
      block-size 280ms var(--ease-in-out),
      content-visibility 280ms allow-discrete;
  }
  .site[data-motion="full"] .site-body details[open] > :not(summary) {
    animation: site-answer-rise 240ms var(--ease-out) 60ms backwards;
  }
}
@keyframes site-answer-fade {
  from {
    opacity: 0;
  }
}
@keyframes site-answer-rise {
  from {
    opacity: 0;
    translate: 0 4px;
  }
}

/* the shade between a light page and the dark one: over everything, the header too, taking no clicks; the colours swap under it */
.site-shade {
  position: fixed;
  inset: 0;
  z-index: 3;
  background: #070f22;
  pointer-events: none;
}

/* ---------- the data centre is dark: the header, the page and its foot ---------- */

.site.dark-page .site-logo img {
  mix-blend-mode: screen;
  filter: invert(1) hue-rotate(180deg);
}

/* ---------- xs and sm (below 768): one column ---------- */

@media (max-width: 767px) {
  .site-logo img {
    height: 22px;
  }
  .site-drive {
    padding: 0 14px;
  }
  .site-body p {
    hyphens: auto;
    hyphenate-limit-chars: 8 4 3;
  }
  /* projects: the name, its picture, then its words */
  .site-body .project-head,
  .site-body .project > .shot {
    order: -1;
  }
  .site-body .project > .shot {
    margin-top: var(--s-5);
  }
  /* the way of working downwards, its line at the left */
  .site-body .process {
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--s-4);
    padding: 0 0 0 var(--s-5);
  }
  .site-body .process::before,
  .site-body .process::after {
    top: 0;
    bottom: 0;
    right: auto;
    width: 1px;
    height: auto;
  }
  .site-body .process::after {
    top: 0;
    left: -0.5px;
    width: 2px;
    transform-origin: top;
  }
  /* the data centre's map from edge to edge, its caption on line A */
  .site-body .network-map {
    margin-inline: calc(-1 * (var(--edge) + var(--safe-left))) calc(-1 * (var(--edge) + var(--safe-right)));
  }
  .site-body .network-map figcaption {
    padding-inline: calc(var(--edge) + var(--safe-left)) calc(var(--edge) + var(--safe-right));
  }
}

/* xs (below 480): the figures as a small table, the number at the left, what it counts at the right */
@media (max-width: 479px) {
  .site-page .onward {
    padding-top: var(--s-6);
  }
  .site-body .figures {
    --figure: 44px;
    --figure-word: calc(44px * 13 / 21);
    grid-template-columns: minmax(0, 1fr);
    row-gap: 0;
  }
  .site-body .figures li {
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--gutter);
    align-items: last baseline;
    padding-block: var(--s-4);
  }
  .site-body .figures li > span {
    grid-area: 1 / 2;
    margin-top: 0;
    text-align: end;
  }
}

/* ---------- md (768 and up): eight columns ---------- */

@media (min-width: 768px) {
  .site-page .onward {
    padding-top: var(--s-7);
  }
  /* start: the title over the whole width; the lead and the index in the first half, the plan in the second, one line under both */
  .site-body .sections > section:has(> .site-plan):not([hidden]) {
    grid-template-rows: auto auto minmax(0, 1fr) auto;
  }
  .site-body .sections > section:has(> .site-plan) > .lead {
    grid-row: 2;
  }
  .site-body .sections > section:has(> .site-plan) > .cards {
    grid-row: 3;
    align-self: stretch;
    display: grid;
    grid-auto-rows: minmax(min-content, 1fr);
  }
  .site-body .sections > section > .site-plan {
    grid-row: 2 / span 3;
    display: grid;
    grid-template-rows: subgrid;
    margin-top: 0;
  }
  /* (at least square – a block as tall as the column is wide holds it open –, taller where the index beside it is) */
  .site-plan-map {
    grid-row: 1 / span 2;
    aspect-ratio: auto;
  }
  .site-plan-map::before {
    content: "";
    display: block;
    padding-top: 100%;
  }
  .site-plan-caption {
    grid-row: 3;
  }
  /* (beside the name, the text's top is trimmed like the name's: their first baselines meet, and the name's caps stay on the row's padding) */
  .site-body :is(.service-list p, .cities) {
    margin-top: calc(0.656em - var(--source-base));
  }
  /* about: the strengths side by side */
  .site-body .sections > section > .facts {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .site-body .sections > section > .facts li {
    padding: calc(var(--s-5) + 0.734em - var(--satoshi-base)) 0 0;
  }
  /* (side by side they are one row: nothing to close) */
  .site-body .sections > section > .facts li:last-child::after {
    content: none;
  }
  /* the foot in one line: the languages over the page's centre */
  .site-foot {
    display: grid;
    grid-template-columns: minmax(max-content, 1fr) auto minmax(max-content, 1fr);
  }
  .site-foot .languages {
    margin-inline: 0;
  }
  .site-foot .legal {
    justify-self: end;
  }
}

/* md only: the first half (five of eight columns) and the second; a project's picture over the width, at most 4:3, a taller one keeps its top (the archived one smaller) */
@media (min-width: 768px) and (max-width: 1023px) {
  .site-body .sections > section > :is(.lead, .person, .person ~ p, .contact-row, .brief, details) {
    grid-column: 1 / 7;
  }
  .site-body .sections > section:has(> .site-plan) > :is(.lead, .cards) {
    grid-column: 1 / 5;
  }
  .site-body .sections > section > .site-plan:not([hidden]) + .cards {
    margin-top: var(--s-8);
  }
  .site-body .sections > section > .site-plan {
    grid-column: 5 / 9;
  }
  .site-body .project > :is(.lead, p) {
    grid-column: 1 / 7;
  }
  .site-body .project .facts {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: var(--gutter);
  }
  .site-body .project .facts li:last-child::after {
    content: none;
  }
  .site-body .service-list h3,
  .site-body .region-name {
    grid-column: 1 / 5;
  }
  .site-body .service-list p,
  .site-body .cities,
  .site-body .sections > section > .form-note {
    grid-column: 5 / 9;
  }
  .site-body .project-head,
  .site-body .project > .shot {
    order: -1;
  }
  .site-body .project > .shot {
    margin-top: var(--s-5);
    container-type: inline-size;
  }
  /* (never taller than 4:3: a tall picture loses its bottom, a wide one stays whole) */
  .site-body .project > .shot img {
    max-block-size: 75cqi;
    object-fit: cover;
    object-position: 50% 0;
  }
  .site-body .project > .shot.archived {
    grid-column: 1 / 6;
  }
}

/* ---------- lg (1024 and up): twelve columns ---------- */

@media (min-width: 1024px) {
  .site-body .sections > section > .lead {
    grid-column: 1 / 8;
  }
  .site-body .sections > section:has(> .site-plan) > :is(.lead, .cards) {
    grid-column: 1 / 7;
  }
  .site-body .sections > section > .site-plan:not([hidden]) + .cards {
    margin-top: var(--s-9);
  }
  .site-body .sections > section > .site-plan {
    grid-column: 7 / 13;
  }
  /*
   * A project as a spread: its words in five columns, its picture in six
   * beside them (mirrored every other one; the archived one smaller). The
   * name's caps stand on the picture's top edge; where the words are
   * shorter, the facts and the button close on its bottom edge (the row
   * before them takes the rest).
   */
  .site-body .project {
    grid-template-rows: repeat(6, auto) minmax(0, 1fr) auto auto;
    align-items: start;
  }
  .site-body .sections > section > .project {
    padding-top: var(--s-8);
  }
  .site-body .project > * {
    grid-column: 1 / 6;
  }
  .site-body .project > .shot {
    grid-column: 7 / -1;
    grid-row: 1 / -1;
  }
  .site-body .project:nth-of-type(even) > * {
    grid-column: 8 / -1;
  }
  .site-body .project:nth-of-type(even) > .shot {
    grid-column: 1 / 7;
  }
  .site-body .project:has(> .shot.archived) > * {
    grid-column: 1 / 7;
  }
  .site-body .project:has(> .shot.archived) > .shot {
    grid-column: 9 / -1;
  }
  .site-body .project > .facts {
    grid-row: -3;
  }
  .site-body .project > :is(.button, .form-note) {
    grid-row: -2;
  }
  .site-body .service-list h3 {
    grid-column: 1 / 7;
  }
  .site-body .service-list p {
    grid-column: 7 / 12;
  }
  /* about: the person beside the lead, its line on the lead's caps */
  .site-body .sections > section:has(> .person) > .lead {
    grid-row: 2;
  }
  .site-body .sections > section > .person {
    grid-column: 9 / -1;
    grid-row: 2 / span 2;
    align-self: start;
    margin-top: var(--title-gap);
  }
  .site-body .sections > section > .person ~ p {
    grid-column: 1 / 8;
    grid-row: 3;
  }
  .site-body .person img {
    width: 72px;
    height: 72px;
  }
  /* contact: the form at the left, the address and the questions in a side column */
  .site-body .sections > section:has(> .brief):not([hidden]) {
    grid-template-rows: auto auto auto auto auto minmax(0, 1fr);
    align-items: start;
  }
  .site-body .sections > section > .contact-row {
    grid-column: 9 / -1;
    grid-row: 2;
  }
  .site-body .sections > section > .brief {
    grid-column: 1 / 8;
    grid-row: 2 / span 5;
    margin-top: var(--intro-gap);
  }
  .site-body .sections > section > details {
    grid-column: 9 / -1;
  }
  .site-body summary {
    font-size: 18px;
  }
  /* the data centre: four figures in a row, a continent's count beside its name */
  .site-body .figures {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .site-body .region-name {
    grid-column: 1 / 7;
    display: grid;
    /* (four of its six columns for the name, the count from the fifth) */
    grid-template-columns: calc((100% - 5 * var(--gutter)) * 4 / 6 + 3 * var(--gutter)) minmax(0, 1fr);
    column-gap: var(--gutter);
    align-items: baseline;
  }
  .site-body .region-name b {
    margin-left: 0;
  }
  .site-body .cities {
    grid-column: 7 / -1;
  }
  .site-body .sections > section > .form-note {
    grid-column: 7 / -1;
  }
}

/* xl (1280 and up): the name and the address side by side */
@media (min-width: 1280px) {
  .site-body .brief {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--gutter);
  }
  .site-body .brief > * {
    grid-column: 1 / -1;
  }
  .site-body .brief > .field:has(> input) {
    grid-column: auto;
  }
}

/* ---------- not as wide (below 1080), or short: the navigation is a sheet under the header ---------- */

@media (max-width: 1079px), (max-height: 540px) and (orientation: landscape) {
  .site-head {
    grid-template-columns: auto minmax(0, 1fr);
  }
  .site-actions {
    grid-column: 2;
  }
  .site-menu {
    display: grid;
  }
  /* while the sheet is open the close button steps aside – it fades, then is gone – and comes back once the menu button is no cross any more */
  .site-close {
    --button-fade: opacity var(--dur-fade) var(--ease-out) 120ms;
  }
  .site-menu[aria-expanded="true"] ~ .site-close {
    visibility: hidden;
    opacity: 0;
    --button-fade: opacity 140ms var(--ease-in), visibility 0s 140ms;
  }
  /*
   * the sheet: under the header, the window's width, its edges the page's.
   * Closed it is there but unseen, clipped to its top edge and taking nothing
   * (inert, ui/site.mjs); it unrolls down from the header, its links coming
   * down with it one after the other and their lines drawing, and rolls back
   * up with its links gone at once. All of it transitions, so a sheet turned
   * round midway turns from where it is. (Out of the header's columns:
   * placed in one, it would take that column for its box, not the header's.)
   */
  .site-nav {
    grid-column: auto;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    max-height: calc(100dvh - var(--head-h) - var(--safe-top));
    overflow-y: auto;
    padding: 0 calc(var(--edge) + var(--sbw) + var(--safe-right)) var(--s-5) calc(var(--edge) + var(--safe-left));
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    background: var(--page);
    visibility: hidden;
    clip-path: inset(0 0 100% 0);
    transition:
      clip-path 280ms var(--ease-in) 40ms,
      visibility 0s 320ms;
  }
  .site-nav.open {
    visibility: visible;
    clip-path: inset(0 0 -1px 0);
    transition:
      clip-path var(--dur-sheet) var(--ease-surface),
      visibility 0s;
  }
  /* a row each, 56 px, a line between them; the current page in ink with a blue bar at its left */
  .site-nav a {
    position: relative;
    display: flex;
    align-items: center;
    block-size: 56px;
    padding: 0 0 0 14px;
    border-radius: 0;
    font-size: var(--heading);
    line-height: 1.15;
    letter-spacing: -0.025em;
    opacity: 0;
    translate: 0 -12px;
    transition:
      opacity 140ms var(--ease-in),
      translate 0s 140ms,
      color var(--dur-tint) var(--ease-out) var(--lit-after, 0ms);
  }
  .site-nav.open a {
    opacity: 1;
    translate: 0 0;
    transition:
      opacity var(--dur-appear) var(--ease-out) calc(80ms + var(--i) * var(--step-sheet)),
      translate 520ms var(--ease-out) calc(80ms + var(--i) * var(--step-sheet)),
      color var(--dur-tint) var(--ease-out) var(--lit-after, 0ms);
  }
  .site-nav a + a::before {
    content: "";
    position: absolute;
    inset: 0 0 auto;
    height: 1px;
    background: var(--line);
    transform-origin: 0 50%;
    scale: 0 1;
    transition: scale 0s 140ms;
  }
  .site-nav.open a + a::before {
    scale: 1 1;
    transition: scale var(--dur-draw) var(--ease-in-out) calc(120ms + var(--i) * var(--step-sheet));
  }
  .site-nav a[aria-current] {
    box-shadow: inset 2px 0 var(--blue);
  }
  /* (on a weak device the sheet only fades, its links and lines simply there, the menu button's lines simply swapped) */
  .site[data-motion="low"] .site-nav {
    clip-path: none;
    opacity: 0;
    transition:
      opacity 160ms var(--ease-in),
      visibility 0s 160ms;
  }
  .site[data-motion="low"] .site-nav.open {
    opacity: 1;
    transition:
      opacity 160ms var(--ease-out),
      visibility 0s;
  }
  .site[data-motion="low"] .site-nav a {
    opacity: 1;
    translate: none;
    transition: color var(--dur-tint) var(--ease-out) var(--lit-after, 0ms);
  }
  .site[data-motion="low"] .site-nav a + a::before {
    scale: none;
    transition: none;
  }
  .site[data-motion="low"] .site-menu path {
    transition: none;
  }
  /* (the menu button is a cross at once: the close button goes at once too, never two crosses side by side, and comes back with a plain fade) */
  .site[data-motion="low"] .site-close {
    --button-fade: opacity var(--dur-fade) var(--ease-out);
  }
  .site[data-motion="low"] .site-menu[aria-expanded="true"] ~ .site-close {
    --button-fade: opacity 0s, visibility 0s;
  }
  .site-nav-mark {
    display: none;
  }
}

/* ---------- short: a phone held sideways ---------- */

@media (max-height: 540px) and (orientation: landscape) {
  .site-logo img {
    height: 20px;
  }
  .site-drive {
    padding: 0 14px;
  }
  .site-nav a {
    block-size: 44px;
  }
  /* the key figures no larger than a short screen bears beside a 40 px title */
  .site-body .figures {
    --figure: clamp(36px, 21cqi, 56px);
    --figure-word: clamp(24px, 13cqi, 35px);
  }
  /* the plan no taller than the screen under the header, in the middle of its column */
  .site-plan-map {
    inline-size: min(100%, calc(100dvh - var(--head-h) - var(--s-8)));
    aspect-ratio: 1;
    min-block-size: 0;
    margin-inline: auto;
    justify-self: center;
    align-self: center;
  }
}
/* (wide enough: the sheet in two columns of three) */
@media (max-height: 540px) and (orientation: landscape) and (min-width: 600px) {
  .site-nav {
    display: grid;
    grid-template-rows: repeat(3, auto);
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    column-gap: var(--gutter);
  }
  .site-nav a:nth-child(3n + 1)::before {
    content: none;
  }
}
/* (on eight columns: a project as a spread too, its picture beside its words) */
@media (max-height: 540px) and (orientation: landscape) and (min-width: 768px) and (max-width: 1023px) {
  .site-body .project {
    grid-template-rows: repeat(6, auto) minmax(0, 1fr) auto auto;
    align-items: start;
  }
  .site-body .project-head,
  .site-body .project > .shot {
    order: 0;
  }
  .site-body .project > :is(.project-head, .lead, p, .facts, .button) {
    grid-column: 1 / 5;
  }
  .site-body .project > .shot {
    grid-column: 5 / -1;
    grid-row: 1 / -1;
    margin-top: 0;
  }
  .site-body .project > .shot.archived {
    grid-column: 6 / -1;
  }
  .site-body .project > .shot img {
    max-block-size: none;
  }
  .site-body .project .facts {
    grid-template-columns: minmax(0, 1fr);
  }
  .site-body .project .facts li:last-child::after {
    content: "";
  }
  .site-body .project > .facts {
    grid-row: -3;
  }
  .site-body .project > :is(.button, .form-note) {
    grid-row: -2;
  }
}

/* narrow phones: the way back to the 3D world says only where it goes ("3D-Welt"; the whole label is still read out), so the logo, it, the menu and the close button stay in one row */
@media (max-width: 420px) {
  .site-drive .drive-more {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
}

/* ---------- forced colours: the mark under the current page in the system's highlight ---------- */

@media (forced-colors: active) {
  .site-shade,
  .site-scrim {
    display: none;
  }
  .site-nav-mark {
    background: Highlight;
    forced-color-adjust: none;
  }
}
