/* DataPublication.nrw landing page - design round 2 (denser layout, real content).
   Brand values only in :root below; source: CD package 07-Farben/farbwerte.txt.
   Mobile first. No external requests. Notes: tooling/landing-preview/DESIGN-NOTES.md */

:root {
  /* Brand colours (07-Farben/farbwerte.txt, line number in brackets) */
  --dp-nachtblau: #003064;       /* [4] Hauptfarbe der Marke */
  --dp-cyanblau: #29ABE2;        /* [5] Akzentfarbe, Kachel Publizieren */
  --dp-mittelblau: #2E5C8A;      /* [7] optional fuer abgesetzte Endung */
  --dp-anthrazitblau: #0B2239;   /* [8] Hintergrund dunkler Flaechen */
  --dp-weiss: #FFFFFF;           /* [10] */

  /* Roles */
  --dp-text: var(--dp-anthrazitblau);
  --dp-heading: var(--dp-nachtblau);
  --dp-link: var(--dp-nachtblau);
  --dp-link-hover: var(--dp-mittelblau);
  --dp-surface: var(--dp-weiss);
  --dp-dark: var(--dp-anthrazitblau);
  --dp-on-dark: var(--dp-weiss);
  --dp-accent-on-dark: var(--dp-cyanblau);
  --dp-line: var(--dp-mittelblau);
  --dp-focus: var(--dp-nachtblau);
  --dp-focus-on-dark: var(--dp-cyanblau);

  /* Typography (00-LIESMICH.txt: Open Sans, Hausschrift NRW) */
  --dp-font: "Open Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Tile shape of the Bildmarke: three round corners (28/100), one hard (6/100) */
  --dp-radius: 1.25rem 1.25rem 1.25rem 0.25rem;
  --dp-radius-small: 0.75rem 0.75rem 0.75rem 0.15rem;

  --dp-gutter: 1rem;
  --dp-max: 72rem;
}

/* ---------- Fonts: self-hosted, Latin subset, OFL (assets/fonts/OFL.txt) ---------- */

@font-face {
  font-family: "Open Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("assets/fonts/open-sans-latin-400-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Open Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("assets/fonts/open-sans-latin-600-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Open Sans";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("assets/fonts/open-sans-latin-700-normal.woff2") format("woff2");
}


/* ---------- Base ---------- */

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

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

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  background: var(--dp-surface);
  color: var(--dp-text);
  font-family: var(--dp-font);
  font-size: 1rem;
  line-height: 1.55;
  overflow-wrap: break-word;
}

h1,
h2,
h3,
h4 {
  color: var(--dp-heading);
  line-height: 1.2;
  margin: 0 0 0.5rem;
  hyphens: auto;
}

h1 {
  font-size: clamp(1.875rem, 1.35rem + 2.4vw, 2.875rem);
  font-weight: 700;
}

h2 {
  font-size: clamp(1.5rem, 1.25rem + 1.1vw, 2rem);
  font-weight: 700;
  margin-bottom: 0.75rem;
}

/* Decorative cyan rule under section headings (not information-bearing). */
h2::after {
  content: "";
  display: block;
  width: 2.5rem;
  height: 0.25rem;
  margin-top: 0.4rem;
  background: var(--dp-cyanblau);
  border-radius: 0.125rem;
}

h3 {
  font-size: 1.125rem;
  font-weight: 600;
}

h4 {
  font-size: 1rem;
  font-weight: 600;
}

p {
  margin: 0 0 0.75rem;
}

a {
  color: var(--dp-link);
  text-decoration-thickness: 0.08em;
  text-underline-offset: 0.18em;
}

a:hover {
  color: var(--dp-link-hover);
}

:focus-visible {
  outline: 3px solid var(--dp-focus);
  outline-offset: 3px;
  border-radius: 2px;
}

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

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

.wrap {
  width: 100%;
  max-width: var(--dp-max);
  margin: 0 auto;
  padding-inline: var(--dp-gutter);
}

.lead {
  max-width: 68ch;
  margin-bottom: 1.5rem;
  font-size: 1.0625rem;
}

.band {
  padding-block: 40px;
}

@media (min-width: 900px) {
  .band {
    padding-block: 56px;
  }
}

.band-dark {
  background: var(--dp-dark);
  color: var(--dp-on-dark);
}

.band-dark h1,
.band-dark h2,
.band-dark h3,
.band-dark a:not(.button) {
  color: var(--dp-on-dark);
}

.band-dark :focus-visible {
  outline-color: var(--dp-focus-on-dark);
}

.card {
  border: 2px solid var(--dp-nachtblau);
  border-radius: var(--dp-radius);
  background: var(--dp-surface);
  padding: 20px;
}

@media (min-width: 900px) {
  .card {
    padding: 24px;
  }
}

.card > :last-child,
.card p:last-child {
  margin-bottom: 0;
}

/* ---------- Skip link ---------- */

.skip-link {
  position: absolute;
  left: 1rem;
  top: -10rem;
  z-index: 10;
  padding: 0.5rem 1rem;
  background: var(--dp-nachtblau);
  color: var(--dp-on-dark);
  font-weight: 600;
}

.skip-link:focus {
  top: 1rem;
  color: var(--dp-on-dark);
  outline-color: var(--dp-focus);
}

/* ---------- 0 Header ---------- */

.site-header {
  border-bottom: 1px solid var(--dp-line);
  background: var(--dp-surface);
}

.header-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.25rem 1.5rem;
  padding-block: 0.625rem;
}

/* CD Schutzraum: 1/5 of the block height (40px -> 8px) kept free around the mark. */
.wordmark {
  display: inline-block;
  padding: 0.5rem;
  margin: -0.5rem;
  line-height: 0;
}

.wordmark img {
  height: 40px;
  width: auto;
}

.lang-switch {
  margin: 0;
  font-weight: 600;
}

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

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.25rem;
}

.site-nav a {
  display: inline-block;
  padding-block: 0.25rem;
  font-weight: 600;
  text-decoration: none;
}

.site-nav a:hover,
.site-nav a:focus-visible {
  text-decoration: underline;
}

@media (min-width: 768px) {
  .site-nav {
    order: 0;
    flex-basis: auto;
    margin-left: auto;
  }
}

/* ---------- 1 Hero ---------- */

.hero {
  position: relative;
  overflow: hidden;
  padding-block: 2.25rem 2.5rem;
}

@media (min-width: 900px) {
  .hero {
    padding-block: 3rem 3.25rem;
  }
}

.motif {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
}

.motif-tile {
  fill: var(--dp-nachtblau);
}

.motif-accent {
  fill: var(--dp-cyanblau);
  display: none;
}

/* The cyan accent tile only shows where it cannot sit behind text. */
@media (min-width: 1100px) {
  .motif-accent {
    display: inline;
  }
}

.hero-inner {
  position: relative;
}

.hero-inner > * {
  max-width: 40rem;
}

.hero-inner > h1 {
  max-width: 52rem;
  hyphens: manual;
}

.eyebrow {
  margin-bottom: 0.5rem;
  color: var(--dp-accent-on-dark);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.hero-lead {
  font-size: 1.0625rem;
}

.hero-status {
  color: var(--dp-accent-on-dark);
  font-weight: 600;
}

.counter-hero {
  font-size: 1.0625rem;
  font-weight: 600;
}

.count-n {
  display: inline-block;
  margin-right: 0.15em;
  color: var(--dp-accent-on-dark);
  font-size: 2.5rem;
  font-weight: 700;
  line-height: 1;
  vertical-align: -0.1em;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin: 1.25rem 0 0;
}

.button {
  display: inline-block;
  padding: 0.6rem 1.15rem;
  border: 2px solid transparent;
  border-radius: var(--dp-radius-small);
  font-weight: 600;
  text-decoration: none;
}

.button-primary {
  background: var(--dp-cyanblau);
  color: var(--dp-nachtblau);
}

.button-primary:hover {
  background: var(--dp-weiss);
  color: var(--dp-nachtblau);
}

.button-ghost {
  border-color: var(--dp-weiss);
  color: var(--dp-on-dark);
}

.button-ghost:hover {
  background: var(--dp-weiss);
  color: var(--dp-nachtblau);
}

/* ---------- 2 About ---------- */

.about-grid {
  display: grid;
  gap: 1.25rem;
}

.about-text p {
  max-width: 68ch;
  font-size: 1.0625rem;
}

.facts {
  display: grid;
  gap: 0.75rem;
}

.facts .card {
  padding: 16px 18px;
}

.facts h3 {
  margin-bottom: 0.25rem;
}

/* Below 600px the facts are a plain list: title + text with a decorative cyan bar. */
@media (max-width: 599px) {
  .facts {
    gap: 0.875rem;
  }

  .facts .card {
    padding: 0 0 0 0.875rem;
    border: 0;
    border-left: 4px solid var(--dp-cyanblau);
    border-radius: 0;
    background: none;
  }

  .facts h3 {
    margin-bottom: 0.125rem;
  }
}

@media (min-width: 600px) {
  .facts {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* FDM.NRW figure (CC BY 4.0) with its credit line. */
.about-figure {
  margin: 0;
}

.about-figure img {
  display: block;
  width: 100%;
  border: 1px solid var(--dp-line);
  border-radius: var(--dp-radius-small);
}

.about-figure figcaption {
  margin-top: 0.5rem;
  font-size: 0.875rem;
}

/* Text and figure side by side, six facts below in three columns. */
@media (min-width: 900px) {
  .about-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 1.5rem;
  }

  .about-grid .facts {
    grid-column: 1 / -1;
  }

  .facts {
    grid-template-columns: repeat(3, 1fr);
  }
}

/* ---------- 3 Workflow ---------- */

/* The logo mark beside the heading: its four tiles are the four steps below. */
.workflow-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1.25rem;
}

.workflow-head h2 {
  margin-bottom: 0;
}

.workflow-mark {
  flex: none;
  display: block;
  width: 56px;
  height: auto;
}

@media (min-width: 960px) {
  .workflow-mark {
    width: 88px;
  }
}

.tiles {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
}

@media (min-width: 560px) {
  .tiles {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 960px) {
  .tiles {
    grid-template-columns: repeat(4, 1fr);
  }
}

.tile-head {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
}

.tile-icon {
  flex: none;
  width: 48px;
  height: 48px;
}

.tile h3 {
  margin: 0;
}

.tile p {
  margin: 0;
}

/* ---------- 4 Progress ---------- */

.progress-grid {
  display: grid;
  gap: 1rem;
}

/* The number on top, the chart below it across the full card width. From
   900px the card takes the row height (set by the news card) and the chart
   fills what is left, so there are no empty bands above and below. Nested
   grids, not a flex column: that collapsed the chart. */
.progress-main {
  display: grid;
  grid-template-rows: auto 1fr;
  gap: 1.25rem;
}

@media (min-width: 900px) {
  .progress-grid {
    grid-template-columns: 2fr 1fr;
    align-items: stretch;
  }

  /* Nothing counted yet (prod before the first live space): news across the width. */
  .progress-grid.is-news-only {
    grid-template-columns: minmax(0, 1fr);
  }

  .is-news-only .news {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1.5rem;
  }

  .is-news-only .news li {
    padding: 0;
    border-bottom: 0;
  }
}

.big-number {
  margin: 0;
  color: var(--dp-nachtblau);
  line-height: 1.05;
}

.big-n {
  font-size: clamp(3.25rem, 2.6rem + 3vw, 4.5rem);
  font-weight: 700;
}

.big-total {
  font-size: 1.75rem;
  font-weight: 600;
}

.big-label {
  display: block;
  font-size: 1rem;
  font-weight: 600;
}

.chart-wrap {
  display: grid;
  grid-template-rows: 1fr auto;
  gap: 0.25rem;
}

.chart {
  display: grid;
  grid-template-rows: 1fr auto;
  gap: 0.5rem;
  margin: 0;
}

.chart figcaption {
  font-size: 0.875rem;
  font-weight: 600;
}

/* Server-rendered chart (landing.py): the SVG stretches, the labels are HTML. */
.step-chart {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: 1fr auto;
  gap: 0.375rem 0.5rem;
  color: var(--dp-anthrazitblau);
  font-size: 0.8125rem;
  line-height: 1;
}

.step-chart svg {
  grid-column: 2;
  grid-row: 1;
  display: block;
  width: 100%;
  height: clamp(10rem, 32vw, 14rem);
  overflow: visible;
}

.axis-y {
  grid-column: 1;
  grid-row: 1;
  justify-self: end;
}

/* Centred on the top edge and on the base line of the plot. */
.axis-max {
  align-self: start;
  transform: translateY(-50%);
}

.axis-min {
  align-self: end;
  transform: translateY(50%);
}

.axis-x {
  grid-column: 2;
  grid-row: 2;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding-top: 0.25rem;
}

.step-chart line {
  stroke: var(--dp-mittelblau);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}

.step-chart path {
  fill: none;
  stroke: var(--dp-nachtblau);
  stroke-width: 4;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

@media (min-width: 900px) {
  .step-chart svg {
    height: 100%;
    min-height: 12rem;
  }
}

.data-table summary {
  display: inline-block;
  padding-block: 0.125rem;
  color: var(--dp-link);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: underline;
  cursor: pointer;
}

.data-table table {
  margin-top: 0.5rem;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

.data-table caption {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.data-table th,
.data-table td {
  padding: 0.25rem 1rem 0.25rem 0;
  border-bottom: 1px solid var(--dp-line);
  text-align: left;
}

.news li {
  padding-block: 0.625rem;
  border-bottom: 1px solid var(--dp-line);
}

.news li:first-child {
  padding-top: 0;
}

.news time {
  display: block;
  font-size: 0.8125rem;
  font-weight: 600;
}

.news h4 {
  margin: 0.125rem 0 0.25rem;
}

.news p {
  margin: 0;
  font-size: 0.9375rem;
}

.stand {
  margin: 0.625rem 0 0;
  font-size: 0.8125rem;
}

/* ---------- 5 Universities ---------- */

.uni-grid {
  display: grid;
  gap: 1.25rem;
}

@media (min-width: 1000px) {
  .uni-grid {
    grid-template-columns: 7fr 5fr;
    gap: 2rem;
    align-items: start;
  }
}

.map {
  margin: 0;
  padding: 0.5rem;
}

.dp-map {
  display: block;
  width: 100%;
  height: auto;
}

.legend {
  margin-top: 0.75rem;
}

.legend h3 {
  font-size: 1rem;
}

.legend ul {
  display: grid;
  gap: 0.375rem 1.25rem;
}

@media (min-width: 560px) {
  .legend ul {
    grid-template-columns: repeat(2, 1fr);
  }
}

.legend li {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: 0.9375rem;
  line-height: 1.35;
}

.swatch {
  flex: none;
  margin-top: 0.05rem;
}

.legend-desc {
  display: block;
  font-size: 0.8125rem;
}

.uni-list h3 {
  margin-bottom: 0.25rem;
}

.partners li {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.125rem 0.75rem;
  padding-block: 0.4rem;
  border-bottom: 1px solid var(--dp-line);
}

/* Highlight band behind a row (map <-> list hover, see .uni-grid below),
   a little wider than the row so the text keeps its alignment. */
.partners li::before {
  content: "";
  position: absolute;
  inset: 0 -0.5rem;
  z-index: -1;
  border-radius: var(--dp-radius-small);
  background: var(--row-bg, transparent);
  transition: background-color 0.15s ease-out;
}

.partners a,
.partner-name {
  font-weight: 600;
}

/* Palette shared by map boxes, legend swatches and list badges. The page
   shows no per-university progress (landing.py, PARTNER): every consortium
   university looks the same, only "consortium partner" differs.
   Map labels are small (about 12 px at 1440, 6 px on phones), so the text
   pairs aim well above 4.5:1: white on Mittelblau 6.97:1 (APCA Lc 89),
   Nachtblau on white 13.07:1; boxes against the land >= 6:1 (DESIGN-NOTES.md). */
[data-status="partner"] {
  --st-fill: var(--dp-mittelblau);
  --st-stroke: var(--dp-mittelblau);
  --st-text: var(--dp-weiss);
}

[data-status="external"] {
  --st-fill: var(--dp-weiss);
  --st-stroke: var(--dp-nachtblau);
  --st-text: var(--dp-nachtblau);
}

/* Map artwork, flat and in brand colours: classes from landingStyleHooks
   (map/svgo.config.mjs), which also drops DP.svg's shadow and rounds the
   partner boxes. Land a light Cyanblau tint, rivers cut out in white,
   outline and dots in Nachtblau. */
.dp-map .map-land {
  fill: var(--dp-weiss);
  fill: color-mix(in srgb, var(--dp-cyanblau) 10%, var(--dp-weiss));
  fill-opacity: 1;
}

.dp-map .map-border {
  stroke: var(--dp-nachtblau);
  stroke-opacity: 0.5;
  stroke-width: 3;
}

.dp-map .map-river {
  stroke: var(--dp-weiss);
  stroke-opacity: 1;
}

.dp-map .map-marker {
  fill: var(--dp-nachtblau);
  stroke: var(--dp-weiss);
  stroke-width: 5;
  paint-order: stroke;
}

/* Map <-> list highlight without JavaScript: highlight_css() in landing.py
   puts one rule into the page that sets --chip-fill, --chip-text and --row-bg
   on the hovered or focused partner's chip and row. The values: */
.uni-grid {
  --hl-chip-fill: var(--dp-nachtblau);
  --hl-chip-text: var(--dp-weiss);
  --hl-row-bg: var(--dp-weiss);
  --hl-row-bg: color-mix(in srgb, var(--dp-cyanblau) 15%, var(--dp-weiss));
}

.dp-map rect[data-status],
.swatch rect[data-status] {
  fill: var(--chip-fill, var(--st-fill));
  stroke: var(--chip-fill, var(--st-stroke));
}

/* Not by colour alone: partner boxes are filled without outline, own
   repository is white with an outline. */
.dp-map rect[data-status="partner"],
.swatch rect[data-status="partner"] {
  stroke-width: 0;
}

.dp-map rect[data-status="external"] {
  stroke-width: 4;
}

.swatch rect[data-status="external"] {
  stroke-width: 2;
}

/* Map labels: brand font and colour; sized so every label fits its box
   (DP.svg sets 37px Exo 2 inline). */
.dp-map text {
  fill: var(--chip-text, var(--st-text, var(--dp-nachtblau)));
  font-size: 34px;
}

.map-chip rect,
.map-chip text {
  transition: fill 0.15s ease-out, stroke 0.15s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .map-chip rect,
  .map-chip text,
  .partners li::before {
    transition: none;
  }
}

.dp-map text,
.dp-map tspan {
  font-family: var(--dp-font) !important;
  font-weight: 600 !important;
}

.badge {
  display: inline-block;
  padding: 0 0.55rem;
  border: 1px solid var(--st-stroke);
  border-radius: 999px;
  background: var(--st-fill);
  color: var(--st-text);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
}

.badge[data-status="external"] {
  border-width: 2px;
}

/* ---------- 6 Own space ---------- */

/* Gallery. Default: one running row, three tiles wide (two on phones), paused
   while the pointer is on it. "Show all" opens the same tiles as a grid and
   hides the band. With reduced motion the band stands still. */
.gallery {
  --shot-gap: 1rem;
  --shot-pace: 6s; /* per tile */
  display: flex;
  flex-direction: column;
}

.gallery-band {
  order: -1;
  container-type: inline-size;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 calc(100% - 1.5rem), transparent);
  mask-image: linear-gradient(to right, transparent, #000 1.5rem, #000 calc(100% - 1.5rem), transparent);
}

.gallery-track {
  display: flex;
  width: max-content;
  animation: gallery-run calc(var(--shots) * var(--shot-pace)) linear infinite;
  animation-delay: calc(var(--shots-start) * var(--shot-pace) * -1);
  will-change: transform;
}

.gallery-band:hover .gallery-track {
  animation-play-state: paused;
}

@media (prefers-reduced-motion: reduce) {
  .gallery-track {
    animation-play-state: paused;
  }
}

/* Two equal copies of the row: moving by half the track loops seamlessly. */
@keyframes gallery-run {
  to {
    transform: translateX(-50%);
  }
}

.gallery-row {
  display: flex;
  gap: var(--shot-gap);
  margin: 0;
  padding: 0 var(--shot-gap) 0 0; /* trailing gap, so both copies are equally wide */
  list-style: none;
}

.gallery-row .shot {
  flex: none;
  width: 20rem; /* without container query units */
  width: calc((100cqw - var(--shot-gap)) / 2);
}

@container (min-width: 40rem) {
  .gallery-row .shot {
    width: calc((100cqw - 2 * var(--shot-gap)) / 3);
  }
}

.gallery-all > summary {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
  color: var(--dp-link);
  font-size: 0.9375rem;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}

.gallery-all > summary::-webkit-details-marker {
  display: none;
}

/* Chevron: down to unfold, up to fold. */
.gallery-all > summary::after {
  content: "";
  width: 0.45em;
  height: 0.45em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
}

.gallery-all[open] > summary::after {
  transform: translateY(0.15em) rotate(-135deg);
}

.gallery-all > summary:hover {
  color: var(--dp-link-hover);
}

.gallery-all:not([open]) .gallery-open,
.gallery-all[open] .gallery-closed,
.gallery-all[open] + .gallery-band {
  display: none;
}

.gallery-all .shots {
  margin-top: 1rem;
}

/* The grid: two columns on phones, three from 768 px. */
.shots {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem 1rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 768px) {
  .shots {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.shot-link,
.shot-box {
  display: flex;
  flex-direction: column;
  height: 100%;
  color: inherit;
  text-decoration: none;
}

.shot img,
.shot-missing {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--dp-line);
  border-radius: var(--dp-radius-small);
}

.shot-name {
  margin-top: 0.375rem;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.35;
}

/* Second line: what the tile opens, or that the view is still to come. */
.shot-more {
  font-size: 0.8125rem;
}

.shot-link .shot-more {
  color: var(--dp-link);
  text-decoration: underline;
  text-decoration-thickness: 0.08em;
  text-underline-offset: 0.18em;
}

/* Linked tiles answer hover and keyboard focus; unlinked ones stay still. */
.shot-link:hover img,
.shot-link:focus-visible img {
  border-color: var(--dp-nachtblau);
  box-shadow: 0 0 0 1px var(--dp-nachtblau);
}

.shot-link:hover .shot-more {
  color: var(--dp-link-hover);
}

.note {
  margin: 0.75rem 0 0;
  font-size: 0.8125rem;
}

/* ---------- 7 Onboarding (dark band) ---------- */

.steps {
  counter-reset: step;
  display: grid;
  gap: 1rem;
}

.steps li {
  counter-increment: step;
  position: relative;
  padding-left: 3.25rem;
}

.steps li::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: var(--dp-radius-small);
  background: var(--dp-cyanblau);
  color: var(--dp-nachtblau);
  font-weight: 700;
}

/* Connector: vertical on mobile */
.steps li:not(:last-child)::after {
  content: "";
  position: absolute;
  left: calc(1.125rem - 1px);
  top: 2.25rem;
  bottom: -1rem;
  width: 2px;
  background: var(--dp-cyanblau);
}

.steps h3 {
  margin: 0.375rem 0 0.25rem;
}

.steps p {
  margin: 0;
}

@media (min-width: 900px) {
  .steps {
    grid-template-columns: repeat(4, 1fr);
    gap: 1.5rem;
  }

  .steps li {
    padding-left: 0;
    padding-top: 3rem;
  }

  /* Connector: horizontal on desktop */
  .steps li:not(:last-child)::after {
    left: 2.75rem;
    right: -1rem;
    top: calc(1.125rem - 1px);
    bottom: auto;
    width: auto;
    height: 2px;
  }

  .steps h3 {
    margin-top: 0;
  }
}

.cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
  margin: 1.75rem 0 0;
  font-size: 1.0625rem;
  font-weight: 600;
}

/* ---------- 8 Roadmap ---------- */

/*
 * One line with a marker per phase. Done phases and the current one get a
 * filled marker and a thick segment; the current segment ends in an arrow at
 * --progress (0 to 1, set inline from strings) of the way to the next marker,
 * where the "Wir sind hier" badge sits. Vertical on mobile (left rule),
 * horizontal from 900px (top rule). Shapes are clip-path polygons on the
 * pseudo-elements: ::before is the marker, ::after the segment or arrow.
 */
.timeline {
  --rule: 2px;
  --gap: 1rem;
  --dot: 16px;
  --bar: 4px;
  --head: 14px;
  --head-length: 12px;
  display: grid;
  gap: var(--gap);
  border-left: var(--rule) solid var(--dp-line);
  margin-left: 0.5rem;
  padding-left: 1.5rem;
}

.phase {
  position: relative;
  /* Centre of this phase's marker, relative to the item's top left. */
  --mark-x: calc(-1.5rem - var(--rule) / 2);
  --mark-y: calc(0.2rem + var(--dot) / 2);
}

.phase::before {
  content: "";
  position: absolute;
  z-index: 1;
  left: calc(var(--mark-x) - var(--dot) / 2);
  top: calc(var(--mark-y) - var(--dot) / 2);
  width: var(--dot);
  height: var(--dot);
  box-sizing: border-box;
  border: 2px solid var(--dp-nachtblau);
  border-radius: 50%;
  background: var(--dp-weiss);
}

.phase.is-done::before,
.phase.is-current::before {
  background: var(--dp-nachtblau);
}

/* Thick segment from a done phase down to the next marker. */
.phase.is-done::after {
  content: "";
  position: absolute;
  left: calc(var(--mark-x) - var(--bar) / 2);
  top: var(--mark-y);
  width: var(--bar);
  height: calc(100% + var(--gap));
  background: var(--dp-nachtblau);
}

/* Mobile: the arrow runs down to the badge at the end of the current phase. */
.phase.is-current::after {
  content: "";
  position: absolute;
  left: calc(var(--mark-x) - var(--head) / 2);
  top: var(--mark-y);
  width: var(--head);
  height: calc(100% - var(--mark-y) - 0.6rem);
  background: var(--dp-nachtblau);
  clip-path: polygon(
    calc(50% - var(--bar) / 2) 0,
    calc(50% + var(--bar) / 2) 0,
    calc(50% + var(--bar) / 2) calc(100% - var(--head-length)),
    100% calc(100% - var(--head-length)),
    50% 100%,
    0 calc(100% - var(--head-length)),
    calc(50% - var(--bar) / 2) calc(100% - var(--head-length))
  );
}

.phase-when {
  margin-bottom: 0.125rem;
  font-size: 0.875rem;
  font-weight: 600;
}

.current-label {
  display: inline-block;
  position: relative;
  padding: 0 0.5rem;
  border-radius: 999px;
  background: var(--dp-nachtblau);
  color: var(--dp-weiss);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
}

.now {
  margin: 0.5rem 0 0;
  line-height: 1.2rem;
}

.phase h3 {
  margin-bottom: 0.25rem;
}

.phase-text {
  margin: 0;
  font-size: 0.9375rem;
}

@media (min-width: 900px) {
  .timeline {
    --gap: 1.5rem;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--gap);
    border-left: 0;
    border-top: var(--rule) solid var(--dp-line);
    /* Room above the line for the badge at the arrow. */
    margin: 2.75rem 0 0;
    padding: 1.5rem 0 0;
  }

  .phase {
    --mark-x: calc(var(--dot) / 2);
    --mark-y: calc(-1.5rem - var(--rule) / 2);
  }

  .phase.is-done::after {
    left: var(--mark-x);
    top: calc(var(--mark-y) - var(--bar) / 2);
    width: calc(100% + var(--gap));
    height: var(--bar);
  }

  .phase.is-current::after {
    left: var(--mark-x);
    top: calc(var(--mark-y) - var(--head) / 2);
    width: calc((100% + var(--gap)) * var(--progress, 0.5));
    height: var(--head);
    clip-path: polygon(
      0 calc(50% - var(--bar) / 2),
      calc(100% - var(--head-length)) calc(50% - var(--bar) / 2),
      calc(100% - var(--head-length)) 0,
      100% 50%,
      calc(100% - var(--head-length)) 100%,
      calc(100% - var(--head-length)) calc(50% + var(--bar) / 2),
      0 calc(50% + var(--bar) / 2)
    );
  }

  /* The badge stands above the arrow tip, with a notch pointing at it. */
  .now {
    position: absolute;
    left: calc(var(--mark-x) + (100% + var(--gap)) * var(--progress, 0.5));
    top: calc(var(--mark-y) - var(--head) / 2 - 7px);
    margin: 0;
    transform: translate(-50%, -100%);
  }

  .now .current-label::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 100%;
    border: 5px solid transparent;
    border-top-color: var(--dp-nachtblau);
    transform: translateX(-50%);
  }
}

/* Windows high contrast: keep the line, markers and arrow visible. */
@media (forced-colors: active) {
  .phase.is-done::after,
  .phase.is-current::after,
  .phase.is-done::before,
  .phase.is-current::before {
    background: CanvasText;
    forced-color-adjust: none;
  }
}

/* ---------- 9 Contact + 10 Funding ---------- */

.contact-funding {
  display: grid;
  gap: 1rem;
}

@media (min-width: 1000px) {
  .contact-funding {
    gap: 1.5rem;
  }
}

.contact-list {
  margin: 1rem 0 0;
}

/* E-mail | mailing list | legal notice, in line with the three funding columns. */
@media (min-width: 768px) {
  .contact-list {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1.5rem;
  }
}

/* Same subhead as .funding-block h3 (h3 plus its margin), so all three cards share one. */
.contact-list dt {
  margin-bottom: 0.25rem;
  color: var(--dp-heading);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.2;
  hyphens: auto;
}

.contact-list dd {
  margin: 0 0 0.625rem;
}

.contact-list dd:last-child {
  margin-bottom: 0;
}

.funding-block + .funding-block {
  margin-top: 0.875rem;
  padding-top: 0.875rem;
  border-top: 1px solid var(--dp-line);
}

.funding-block h3 {
  margin-bottom: 0.25rem;
}

.funding-block p {
  margin-bottom: 0.75rem;
}

/* Three columns; the logo rows take the free space above them and line up at the bottom. */
@media (min-width: 1000px) {
  .funding {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 24px;
  }

  .funding-block {
    display: flex;
    flex-direction: column;
  }

  .funding-block + .funding-block {
    margin-top: 0;
    padding-top: 0;
    padding-left: 24px;
    border-top: 0;
    border-left: 1px solid var(--dp-line);
  }

  .funding-block .org-panel {
    margin-top: auto;
  }
}

/* One frame per group, the same height in all three columns, logos centred.
   Later rows (org_minor in landing.py) are smaller. */
.org-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 14px;
  min-height: 9rem;
  padding: 16px;
  border: 1px solid var(--dp-line);
  border-radius: var(--dp-radius-small);
}

.org-panel .org-logos {
  justify-content: center;
}

/* ---------- Logos: partner strip under the hero, operation and funding logos ----------
   Logos keep their original colours (many CD guides forbid recolouring).
   A missing logo shows the name in a dashed box (.logo-missing). */

.band-logos {
  padding-block: 28px;
  border-bottom: 1px solid var(--dp-line);
}

.logos-heading {
  margin-bottom: 1rem;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.logos-heading::after {
  display: none;
}

.logo-grid,
.org-logos {
  margin: 0;
  padding: 0;
  list-style: none;
}

.logo-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem 1rem;
}

@media (min-width: 480px) {
  .logo-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 768px) {
  .logo-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* Six columns only from 1200px, where the wrap is at its max width and a column
   is 166.67px: from 768px no partner logo is squeezed below its width attribute. */
@media (min-width: 1200px) {
  .logo-grid {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 1rem 1.5rem;
  }
}

/* 4px sides: the widest partner logo (158px, LOGO_MAX in landing.py) fits that column. */
.logo-cell {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 84px;
  padding: 8px 4px;
}

/* Display sizes come from landing.py (same visible area, optical factor, caps). */
.logo-cell img {
  display: block;
  max-width: 100%;
  height: auto;
}

.logo-cell img:not([width]) {
  width: auto;
  max-height: 52px;
}

.logo-link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: var(--dp-radius-small);
}

/* Linked logos grow a little on hover and keyboard focus; unlinked ones stay still. */
.logo-link img {
  transition: transform 0.15s ease-out;
}

@media (hover: hover) {
  .logo-link:hover img {
    transform: scale(1.08);
  }
}

.logo-link:focus-visible img {
  transform: scale(1.08);
}

@media (prefers-reduced-motion: reduce) {
  .logo-link img {
    transition: none;
  }
}

.logo-missing .logo-link {
  text-decoration: underline;
}

@media (max-width: 767px) {
  .logo-grid .logo-cell {
    height: 72px;
  }
}

.logo-missing {
  padding-inline: 10px;
  border: 1px dashed var(--dp-line);
  border-radius: var(--dp-radius-small);
  font-size: 0.8125rem;
  line-height: 1.3;
  text-align: center;
}

/* Operation and funding logos: a wrapping row, left-aligned with the text,
   each logo at its width/height attributes (flex: none, never squeezed). */
.org-logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 24px;
}

.org-logos .logo-cell {
  flex: none;
  height: auto;
  padding: 0;
}

.org-logos .logo-missing {
  padding: 4px 10px;
}

.org-logos .logo-cell img:not([width]) {
  max-height: 44px;
}

.org-logos-minor .logo-cell img:not([width]) {
  max-height: 32px;
}

/* ---------- 11 Footer ---------- */

.site-footer {
  padding-block: 2rem;
}

.site-footer h2 {
  font-size: 1.125rem;
}

.site-footer h2::after {
  display: none;
}

.site-footer p {
  max-width: 60ch;
  font-size: 0.9375rem;
}

.footer-inner {
  display: grid;
  gap: 0.5rem 2rem;
}

@media (min-width: 900px) {
  .footer-inner {
    grid-template-columns: 1fr auto;
    align-items: end;
  }
}

.powered-by {
  margin: 0.75rem 0 0;
}

/* Beats .band-dark a:not(.button), which would make the text white on the white chip. */
.site-footer .powered-by a {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 6px 12px;
  border-radius: var(--dp-radius-small);
  background: var(--dp-weiss);
  color: var(--dp-anthrazitblau);
  font-size: 0.8125rem;
  font-weight: 600;
  text-decoration: none;
}

.powered-by img {
  display: block;
  width: auto;
  height: 28px;
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
  font-size: 0.9375rem;
}

/* Build line (landing.py checks the claims at render time). Muted mix of the
   two footer tokens: ~#B6BDC4 on Anthrazitblau = 8.47:1 (DESIGN-NOTES.md).
   Segments never break inside; the line wraps only between them. */
.site-footer .build-info {
  grid-column: 1 / -1;
  max-width: none;
  margin: 0.75rem 0 0;
  color: color-mix(in srgb, var(--dp-on-dark) 70%, var(--dp-dark));
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
}

.build-info > span {
  white-space: nowrap;
}

/* ---------- Motion ---------- */

@media (prefers-reduced-motion: no-preference) {
  a,
  .button {
    transition: color 0.15s ease, background-color 0.15s ease;
  }
}

/* ---------- User guide (guide-jinja.html): sidebar + article ----------
   Content comes from Markdown; images keep their aspect ratio and never
   exceed the column. Open points (<mark class="todo">) stay visible. */

.guide-band {
  padding-block: 32px 48px;
}

.guide-layout {
  display: grid;
  gap: 2rem;
}

.guide-main {
  min-width: 0;
  order: -1; /* article first on small screens, chapter list after it */
}

@media (min-width: 960px) {
  .guide-layout {
    grid-template-columns: 17rem minmax(0, 1fr);
    gap: 3rem;
    align-items: start;
  }

  .guide-main {
    order: 0;
  }

  .guide-nav {
    position: sticky;
    top: 1rem;
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
  }
}

.guide-nav {
  font-size: 0.9375rem;
  line-height: 1.4;
  border-top: 1px solid var(--dp-line);
  padding-top: 1rem;
}

@media (min-width: 960px) {
  .guide-nav {
    border-top: 0;
    padding-top: 0;
  }
}

.guide-nav-heading {
  margin: 1rem 0 0.5rem;
  font-weight: 700;
  color: var(--dp-heading);
}

.guide-nav-heading:first-child {
  margin-top: 0;
}

.guide-nav ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.guide-nav ul ul {
  padding-left: 0.875rem;
  border-left: 1px solid var(--dp-line);
  margin: 0.125rem 0 0.25rem 0.25rem;
}

.guide-nav li a {
  display: block;
  padding: 0.25rem 0.5rem;
  border-radius: var(--dp-radius-small);
  text-decoration: none;
}

.guide-nav li a:hover {
  text-decoration: underline;
}

.guide-nav a[aria-current="page"] {
  background: var(--dp-nachtblau);
  color: var(--dp-weiss);
}

/* "Vorläufige Fassung" on provisional plain pages: visible, but calmer than a warning. */
.provisional-note {
  margin: 0 0 1.5rem;
  padding: 0.75rem 1rem;
  border-left: 4px solid var(--dp-cyanblau);
  border-radius: 0 var(--dp-radius-small) var(--dp-radius-small) 0;
  background: color-mix(in srgb, var(--dp-cyanblau) 12%, var(--dp-weiss));
  color: var(--dp-text);
}

.draft-note {
  margin-bottom: 1rem;
  padding: 0.5rem 0.75rem;
  border: 1px dashed var(--dp-line);
  border-radius: var(--dp-radius-small);
  font-size: 0.875rem;
}

.guide-main h1 {
  margin-bottom: 1rem;
  font-size: clamp(1.75rem, 1.4rem + 1.2vw, 2.25rem);
  line-height: 1.2;
  color: var(--dp-heading);
}

.guide-content {
  max-width: 72ch;
}

.guide-content > * + * {
  margin-top: 0.875rem;
}

.guide-content h2,
.guide-content h3,
.guide-content h4 {
  margin-top: 2rem;
  color: var(--dp-heading);
}

.guide-content h2::after {
  display: none;
}

.guide-content h2 {
  font-size: 1.375rem;
}

.guide-content h3 {
  font-size: 1.1875rem;
}

.guide-content ul,
.guide-content ol {
  padding-left: 1.5rem;
}

.guide-content ul {
  list-style: disc;
}

.guide-content ol {
  list-style: decimal;
}

.guide-content li + li {
  margin-top: 0.25rem;
}

.guide-content img {
  max-width: 100%;
  height: auto;
  border: 1px solid var(--dp-line);
  border-radius: var(--dp-radius-small);
}

.guide-content hr {
  border: 0;
  border-top: 1px solid var(--dp-line);
  margin-block: 1.5rem;
}

.guide-content pre {
  overflow-x: auto;
  padding: 0.875rem 1rem;
  border-radius: var(--dp-radius-small);
  background: var(--dp-anthrazitblau);
  color: var(--dp-weiss);
  font-size: 0.875rem;
  line-height: 1.5;
}

.guide-content code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9em;
}

.guide-content :not(pre) > code {
  padding: 0.05em 0.3em;
  border: 1px solid var(--dp-line);
  border-radius: 0.25rem;
}

.guide-content table {
  border-collapse: collapse;
  width: 100%;
  display: block;
  overflow-x: auto;
}

.guide-content th,
.guide-content td {
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--dp-line);
  text-align: left;
  vertical-align: top;
}

.guide-content blockquote {
  margin: 0;
  padding: 0.25rem 0 0.25rem 1rem;
  border-left: 4px solid var(--dp-line);
}

.callout {
  padding: 0.75rem 1rem;
  border-left: 4px solid var(--dp-cyanblau);
  border-radius: 0 var(--dp-radius-small) var(--dp-radius-small) 0;
  box-shadow: inset 0 0 0 1px var(--dp-line);
}

.callout-warning {
  border-left-color: var(--dp-nachtblau);
}

mark.todo {
  padding: 0.05em 0.3em;
  border-radius: 0.2rem;
  background: var(--dp-cyanblau);
  color: var(--dp-nachtblau);
  font-weight: 600;
}

.guide-content blockquote.todo-note {
  border: 1px dashed var(--dp-nachtblau);
  border-radius: var(--dp-radius-small);
  padding: 0.5rem 0.75rem;
  font-size: 0.9375rem;
}

.guide-children {
  margin-top: 2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--dp-line);
}

.guide-children h2 {
  font-size: 1.125rem;
}

.guide-children h2::after {
  display: none;
}

.guide-children ul {
  padding-left: 1.25rem;
}

.guide-pager {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
  margin-top: 2.5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--dp-line);
}

.guide-pager span {
  display: block;
  font-size: 0.8125rem;
  color: var(--dp-text);
}

.guide-next {
  margin-left: auto;
  text-align: right;
}

/* ---------- Plain pages (legal notice, privacy, accessibility) ---------- */

.plain-article {
  max-width: 72ch;
}

.plain-article h1 {
  margin-bottom: 1rem;
  font-size: clamp(1.75rem, 1.4rem + 1.2vw, 2.25rem);
  line-height: 1.2;
  color: var(--dp-heading);
}
