/* __________________________________________________________________________________ */
/* ______________________________[[[  Allgemein  ]]]_________________________________ */
/* __________________________________________________________________________________ */


* {
    margin: 0;
    box-sizing: border-box;
    text-decoration: none;
    border: none;
}

::-webkit-scrollbar {
    display: none;
}

html {
    scrollbar-width: none;

    /* iOS vergrößert Schrift in schmalen Spalten von sich aus — auf dem
       iPhone kam alles rund sieben Prozent größer heraus als hier gerechnet,
       weshalb Intro und Knopfreihe dort nicht aufgingen, obwohl die Maße
       stimmten. Die Seite bringt ihre Größen über clamp() selbst mit. */
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;

    overscroll-behavior: none; /* Deaktiviert das Bouncing */
    max-width: 100vw;
    scroll-behavior: smooth;
    overflow-x: clip; /* nicht hidden: das würde position: sticky aushebeln */

}

/* Nur auf der Startseite: Es gibt dort zwei Zustände — Karte oben oder Intro
   oben. Ein Scroll fährt die ganze Strecke, statt zäh dazwischen zu hängen.
   Auf den Unterseiten wird normal gescrollt. */
html.is-home {
    scroll-snap-type: y mandatory;
}

/* Während des Ladens aus: Sonst sucht sich der Browser beim Neuladen selbst
   einen Snap-Punkt und bleibt beim Intro stehen. index.js nimmt die Klasse
   wieder weg, sobald die Seite steht. */
html.is-home.kein-snap {
    scroll-snap-type: none;
    scroll-behavior: auto;
}

button:hover {
    cursor: pointer;
}

/* Beschriftungen von Bedienelementen sollen sich nicht mitmarkieren, wenn
   über die Karte gezogen wird. Fließtext bleibt überall markierbar. */
.pin,
.scroll-cue,
.lang-switch {
    user-select: none;
    -webkit-user-select: none;
}

body {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    align-items: center;
    text-rendering: optimizeLegibility;
    /* Kein -webkit-font-smoothing: antialiased — das dünnt helle Schrift auf
       dunklem Grund aus. Es ist für dunkle Schrift auf hellem Grund gedacht. */
    background: var(--blue);
}

section {
    width: 100vw;
}


/* ====================[[[  Colors  ]]]==================== */


/* Werte aus dem Druck-PDF der Studierenden gemessen.
   Verbindlich sind die RGB-Werte aus der CI-Originaldatei (Gruppe 1). */
:root {
    --red: rgb(123, 25, 25);
    --blue: #0014A5;
    --yellow: #BE9F00;
    --yellow-bright: #E8C400;
    --grey: #301D38;
    --offwhite: #F4F2EC;
    
    
    --red: #9a182b;             /*Vorgegeben*/
    --blue: #203b73;            /*Vorgegeben*/
    --yellow: #c9a302;          /*Vorgegeben*/
    --green: #016930;           /*Vorgegeben*/


    --card-width: 19rem;
}


/* ====================[[[  Font  ]]]==================== */


h3, p {
    all: unset;
    display: block;
}

/* Die CI-Schnitte der Studierenden liegen noch nicht vor.
   Dateien in fonts/ ablegen, dann greifen die drei Familien automatisch. */
@font-face {
    font-family: "dml";
    src: url("fonts/dml-Regular.woff2") format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: "dml-bold";
    src: url("fonts/dml-Bold.woff2") format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

h3 {
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
    font-size: clamp(1rem, 1.35vw, 1.2rem);
    line-height: 1.2;
    letter-spacing: -0.01em;
}

p, a, li {
    font-family: "dml", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: clamp(0.95rem, 1.05vw, 1.075rem);
    letter-spacing: 0.005em;
    line-height: 1.6;
    color: var(--offwhite);
}

strong {
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
}


/* __________________________________________________________________________________ */
/* ________________________________[[[  Hero  ]]]____________________________________ */
/* __________________________________________________________________________________ */


/* Kopfzeile und Karte teilen sich eine Sektion über die volle Bildschirmhöhe.
   Sie bleibt stehen, während das Intro darüber geschoben wird — innerhalb der
   Sektion bewegt sich dabei nichts. Der Inhalt endet 6rem über der Unterkante:
   In diesem Streifen steht der Scroll-Anzeiger, mit Abstand zur Karte. */
#hero {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;

    /* Der Mindestabstand steht hier statt als Rand an der Karte: Die Karte
       braucht ihre beiden senkrechten Ränder für „auto" (siehe .map-container),
       und ein Abstand im Container wird vor dem freien Raum verteilt — der
       Abstand zur Kopfzeile bleibt also erhalten, egal wo die Karte steht. */
    row-gap: clamp(1.25rem, 3vh, 2.25rem);

    height: 100svh;
    padding-bottom: 6rem;
    scroll-snap-align: start;
}


/* ====================[[[  Scroll-Anzeiger  ]]]==================== */


/* Ohne Hinweis wirkt die Karte wie die ganze Seite — das Intro hat keinen
   eigenen Hintergrund, ein angeschnittener Streifen davon zeigte nur eine
   halbe Textzeile. Deshalb ein Anzeiger statt eines sichtbaren Streifens. */
/* Einzeilig und flach, damit er in den Rand unter den Kartenrahmen passt
   und dessen gelbe Kante nicht schneidet. */
.scroll-cue {
    position: absolute;
    left: 50%;
    bottom: clamp(1.6rem, 3.2vh, 2.4rem);
    z-index: 15;
    display: flex;
    align-items: center;
    gap: 0.55rem;
    transform: translateX(-50%);
    cursor: pointer;

    /* blendet aus, sobald das Intro hochkommt — Wert setzt das Skript */
    opacity: var(--cue-opacity, 1);
    transition: opacity 0.25s ease;
}

.scroll-cue-label {
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
    font-size: 0.78rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    line-height: 1;
    color: var(--yellow-bright);
}

/* Winkel aus zwei Kanten — kein zusätzliches Bild nötig */
.scroll-cue-arrow {
    display: block;
    width: 0.5rem;
    height: 0.5rem;
    border-right: 2px solid var(--yellow-bright);
    border-bottom: 2px solid var(--yellow-bright);
    margin-bottom: 0.22rem; /* Winkelspitze auf die Textmitte */
    transform: rotate(45deg);
    animation: cue-nudge 2s ease-in-out infinite;
}

.scroll-cue:hover .scroll-cue-arrow {
    animation-play-state: paused;
}

@keyframes cue-nudge {
    0%, 100% { transform: rotate(45deg) translate(0, 0); }
    50%      { transform: rotate(45deg) translate(0.2rem, 0.2rem); }
}

@media (prefers-reduced-motion: reduce) {
    .scroll-cue-arrow {
        animation: none;
    }
}


/* __________________________________________________________________________________ */
/* _______________________________[[[  Header  ]]]___________________________________ */
/* __________________________________________________________________________________ */


/* Positioniert mit z-index, damit das Untermenü über der Karte liegt:
   Der Weichzeichner macht die map-container zu einem eigenen Stapelkontext,
   der sonst später gezeichnet würde als die Kopfzeile. */
#header {
    position: relative;
    z-index: 20;
    flex: 0 0 auto;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: clamp(0.75rem, 1.1vw, 1rem) clamp(1rem, 2.5vw, 2.5rem) clamp(0.4rem, 0.6vw, 0.5rem);
}

.wordmark {
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
    font-size: clamp(1rem, 1.5vw, 1.35rem);
    line-height: 1.05;
    letter-spacing: -0.02em;
    color: var(--yellow-bright);
    cursor: pointer;
}

.nav-list,
.nav-list li {
    line-height: 1.2;
}

.nav-list {
    display: flex;
    align-items: center;
    gap: clamp(0.9rem, 1.6vw, 1.75rem);
    list-style: none;
    padding: 0;
}

.nav-list a,
.submenu-trigger {
    position: relative;
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
    font-size: clamp(0.95rem, 1.05vw, 1.075rem);
    line-height: 1.2;
    letter-spacing: 0.005em;
    background: none;
    padding: 0 0 0.15em;
    color: var(--yellow-bright);
    cursor: pointer;
}

/* Unterstrich als Hover-Marke, passend zur gepunkteten CI-Linie */
.nav-list a::after,
.submenu-trigger::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    width: 100%;
    height: 2px;
    background: var(--yellow-bright);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform 0.25s ease;
}

.nav-list a:hover::after,
.nav-list a:focus-visible::after,
.submenu-trigger:hover::after,
.submenu-trigger:focus-visible::after,
.has-submenu:focus-within .submenu-trigger::after {
    transform: scaleX(1);
}

.has-submenu {
    position: relative;
}

/* Rechts verankert und ohne Umbruch: Die Projekttitel sind lang, das Feld
   richtet sich nach ihnen und läuft dabei nicht aus dem Fenster. */
.submenu {
    position: absolute;
    top: 100%;
    right: 0;
    white-space: nowrap;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin-top: 0.6rem;
    padding: 0.75rem 0.9rem;
    list-style: none;
    background: var(--grey);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-0.35rem);
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0.2s;
}

.has-submenu:hover .submenu,
.has-submenu:focus-within .submenu {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}


/* ====================[[[  Sprachwahl  ]]]==================== */


/* Kein weiterer Menüpunkt, sondern ein Schalter: zwei Felder, das aktive
   ausgefüllt — als Kippschalter lesbar, nicht als Link. */
.lang-switch {
    display: flex;
    align-items: stretch;
    padding: 0;
    background: none;
    outline: 2px solid var(--yellow-bright);
    outline-offset: 0;
}

.lang-option {
    display: block;
    padding: 0.25em 0.6em;
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
    font-size: clamp(0.8rem, 0.9vw, 0.9rem);
    line-height: 1.3;
    letter-spacing: 0.04em;
    color: var(--yellow-bright);
    transition: background-color 0.2s ease, color 0.2s ease;
}

.lang-option.is-active {
    background: var(--yellow-bright);
    color: var(--blue);
}

.lang-switch:hover .lang-option:not(.is-active) {
    background: rgba(232, 196, 0, 0.25);
}

.lang-switch:focus-visible {
    outline-color: var(--offwhite);
}


/* __________________________________________________________________________________ */
/* _________________________________[[[  Map  ]]]____________________________________ */
/* __________________________________________________________________________________ */


/* Alles zur Karte liegt hier drin und wird an den Kanten beschnitten.
   Der Container selbst bewegt sich nie — nur die Karte darin. */
.map-container {
    position: relative;
    flex: 1 1 auto;

    /* Nie höher als breit. Auf hochformatigen Fenstern würde der Container
       sonst immer weiter in die Höhe wachsen, während die Karte mit ihrem
       Verhältnis von 1,5:1 in der Mitte stehen bleibt — oben und unten bliebe
       nur leeres Blau. 80vw sind vier Fünftel der Breite, also höchstens 5:4.
       Die Angabe wirkt von selbst nur dort, wo sie gebraucht wird: Ist das
       Fenster flacher als 5:4, greift sie nie. */
    max-height: 80vw;

    /* Sobald die Deckelung greift, bleibt unter der Karte Platz übrig. Ohne
       diese Ränder klebte sie dann an der Kopfzeile und das Blau sammelte
       sich unten. „auto" auf beiden Seiten teilt den Rest gleichmäßig, die
       Karte steht also senkrecht mittig. Steht die Projektliste darunter,
       nimmt die den Rest über flex-grow — dann bleibt für die Ränder nichts
       übrig und die Karte rückt von selbst wieder nach oben. */
    margin-block: auto;

    overflow: hidden;
    background: var(--blue);
}

/* Der Weichzeichner steht bewusst NICHT dauerhaft an der Karte. Ein Filter —
   auch einer mit 0 px — schiebt alles darin durch die Filter-Pipeline, und die
   animierten Punkte und die Maske der Weglinie hinterlassen dort Reste, die
   der Browser nicht wieder aufräumt. initIntroOverlay() setzt die Klasse
   deshalb nur, solange das Intro die Karte tatsächlich überdeckt. */
.weichzeichnen .map-container {
    filter: blur(var(--map-blur, 0px));
}

/* Der gelb gerahmte Kasten ist die Karte. Maße setzt layoutMap(). */
.map-frame {
    position: absolute;
    overflow: hidden;
    outline: 3px solid var(--yellow);
    outline-offset: 0;
    transition: transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
    will-change: transform;
}

/* Trägt Bild und Stationen und ist höher als der Rahmen: Der Ausschnitt
   wird so verschoben, dass alle Stationen im Rahmen liegen. */
.map-plane {
    position: absolute;
    left: 0;
    width: 100%;
}

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


/* ====================[[[  Pins  ]]]==================== */


/* Alle Maße hängen an --map-w, der Kartenbreite in Pixeln, die index.js
   setzt. Dadurch wachsen und schrumpfen die Punkte mit der Karte statt für
   sich allein. 2,513 % ist der Durchmesser der Punkte in der Kartendatei. */
.pin {
    --dot: calc(var(--map-w, 60rem) * 0.02513);
    /* So viel größer wird der Punkt, wenn er angefasst wird. Steht hier als
       Variable, weil schmale Schirme sie weiter aufdrehen. */
    --wuchs: 1.75;
    position: absolute;
    top: var(--y);
    left: var(--x);
    width: calc(var(--dot) * 2.4);
    height: calc(var(--dot) * 2.4);
    margin: calc(var(--dot) * -1.2) 0 0 calc(var(--dot) * -1.2);
    background: none;
    z-index: 5;
    transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Der sichtbare Punkt — eigenes Element, damit die Trefferfläche größer bleibt */
.pin-dot {
    /* Absolut statt im Raster zentriert: Der Punkt wächst über seine Maße,
       und im Raster hätte er dafür keinen Platz — sobald er größer wird als
       seine Trefferfläche, rückt eine Ausrichtung an der Kante nach vorn und
       der Punkt verspringt. Über top/bottom steht die Kante fest, egal wie
       groß er gerade ist. */
    position: absolute;
    left: 50%;
    top: 50%;
    translate: -50% -50%;

    /* Der Kasten ist IMMER so groß wie der gewachsene Punkt und ändert seine
       Maße nie. Gewachsen wird über transform: scale().

       Das ist der Grund: Ändert der Punkt beim Wachsen seine Breite, muss der
       Browser jedes Bild neu bestimmen, welchen Bereich er putzen soll. Dabei
       bleiben senkrechte Streifen des alten Punktes stehen — die Fragmente.
       Bei einem Kasten, der sich nie ändert, kann das nicht passieren.

       Unscharf wird dabei nichts: Gerastert wird in der GRÖSSTEN Größe, im
       Ruhezustand wird heruntergerechnet. Verkleinern ist scharf — nur das
       Vergrößern eines fertig gerasterten Bildes wäre es nicht, und genau
       das passiert hier nicht mehr. */
    width: calc(var(--dot) * var(--wuchs));
    height: calc(var(--dot) * var(--wuchs));
    transform: scale(calc(1 / var(--wuchs)));

    border-radius: 50%;
    background: var(--yellow);

    transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1),
                background-color 0.3s ease;

    /* Jeder Punkt taucht auf, wenn die Linie bei ihm ankommt. Wann das ist,
       rechnet index.js aus dem Pfad und setzt es als animation-delay. Der
       Wert hier ist nur die Rückfallebene, falls das nicht zustande kommt —
       dann erscheinen alle Punkte gemeinsam mit dem Beginn der Linie.
       Animiert wird die eigenständige Eigenschaft scale, nicht transform:
       transform gehört dem Hover, beides zusammen würde sich überschreiben. */
    opacity: 0;
    scale: 0.4;
    animation: punkt-auf 0.45s 1.2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes punkt-auf {
    to { opacity: 1; scale: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .pin-dot {
        animation-duration: 0.01s;
        animation-delay: 0s;
    }
}


.pin:hover .pin-dot,
.pin:focus-visible .pin-dot,
.pin.is-active .pin-dot {
    background: var(--yellow-bright);
    transform: scale(1);
}

.pin:focus-visible {
    outline: 2px solid var(--yellow-bright);
    outline-offset: 2px;
}

/* Der aktive Pin bleibt immer über der Infokarte */
.pin.is-active {
    z-index: 12;
}

/* Die beiden Stationen außerhalb des Kartenausschnitts liegen im Rand des
   Containers und bewegen sich nie: Beim Hover weicht nur die Karte zurück.
   Genau deshalb bleibt der Zeiger auf ihnen und der Hover kippt nicht.
   Sie sehen aus wie alle anderen Punkte. */

/* Sie liegen nicht am Weg und tauchen deshalb nicht mit ihm auf, sondern
   stehen von Anfang an da. */
.pin-outside .pin-dot {
    animation: none;
    opacity: 1;
    scale: 1;
}

/* Weicht die Karte für den einen Außen-Punkt zurück, schiebt sich ihre Kante
   über den anderen. Der tritt deshalb ab, im selben Takt wie die Bewegung. */
.pin.is-verdeckt {
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Der Rand ist nur so breit wie der Punkt selbst. Wüchse er beim Hover aus
   seiner Mitte heraus, schnitte ihn die Containerkante an. Er wächst deshalb
   zur Karte hin — dort liegt er ohnehin über allem.

   Das macht transform-origin: Der Punkt wächst von seiner zur Karte
   abgewandten Kante weg, die dadurch stehen bleibt. Die Kastenmaße bleiben
   unverändert, deshalb stimmen top/bottom weiter — sie legen die Kante des
   ruhenden Punktes fest. */
.pin-nord .pin-dot {
    transform-origin: top center;
    top: calc(50% - var(--dot) / 2);   /* Oberkante steht, er wächst nach unten */
    translate: -50% 0;
}

.pin-sued .pin-dot {
    transform-origin: bottom center;
    top: auto;
    bottom: calc(50% - var(--dot) / 2); /* Unterkante steht, er wächst nach oben */
    translate: -50% 0;
}

/* Gepunktete Verbindung vom Pin zur Kartenkante.
   Die Höhe setzt das Skript, sie wächst beim Zurückweichen mit. */
.pin-leader {
    /* Genau das Muster der Weglinie: Punkt 40, Takt 80 Einheiten der
       Kartendatei, also 0,5376 % und 1,0752 % der Kartenbreite. Ein
       border-style: dotted kann das nicht — der bestimmt Größe und Takt
       selbst und traf beides nicht. */
    --punkt: calc(var(--map-w, 60rem) * 0.005376);
    --takt:  calc(var(--map-w, 60rem) * 0.010752);

    position: absolute;
    left: 50%;
    width: var(--punkt);
    height: 0;
    transform: translateX(-50%);

    /* Das Übergangsband liegt mittig auf der Kante (±0,5 px). Ein harter
       Farbwechsel wird nicht kantengeglättet — der Punkt sähe bei 11 px aus
       wie ein abgerundetes Quadrat. Nach innen gezogen wäre er zu klein.
       So gemessen gegen die Punkte der Weglinie: gleiche Fläche, gleiche
       Höhe, gleich viele weiche Randpixel. */
    background-image: radial-gradient(circle closest-side,
                                      var(--yellow) calc(100% - 0.5px),
                                      transparent calc(100% + 0.5px));
    background-size: var(--punkt) var(--takt);
    background-repeat: repeat-y;
    background-position: 50% 0;

    transition: height 0.7s cubic-bezier(0.22, 1, 0.36, 1);
    pointer-events: none;
}

/* Der südliche Punkt hängt unter der Karte, seine Linie wächst nach oben —
   das Muster muss deshalb an seinem Punkt beginnen, nicht an der Kartenkante. */
.pin-sued .pin-leader {
    background-position: 50% 100%;
}


/* ====================[[[  Weg  ]]]==================== */


/* Liegt deckungsgleich über der Karte. preserveAspectRatio="none", damit
   Pfad und Bild in jeder Größe exakt aufeinanderliegen. */
.weg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
    pointer-events: none;
}

/* Punktmuster wie im gedruckten Original: Punkt 40, Abstand 80 Einheiten
   der Kartendatei. Länge 0 plus runde Enden ergibt den runden Punkt. */
.weg-linie {
    fill: none;
    stroke: var(--yellow);
    stroke-width: 40;
    stroke-linecap: round;
    stroke-dasharray: 0 80;
}

/* Der Aufbau läuft nicht über die Linie selbst, sondern über eine Maske, die
   sie freigibt — das Punktmuster bleibt dadurch unangetastet. */
.weg mask path {
    fill: none;
    stroke: #fff;
    stroke-width: 90;
    stroke-linecap: round;
    stroke-linejoin: round;
    animation: weg-auf linear forwards;
}

@keyframes weg-auf {
    to { stroke-dashoffset: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .weg mask path { animation: none; stroke-dashoffset: 0 !important; }
}


/* ====================[[[  U-Bahn  ]]]==================== */


/* Nachgebaute Haltestellenzeichen — gewöhnliche divs mit abgerundeten Ecken.
   Lage, Farbe und Radius sind aus der PSD abgemessen, in Prozent der Karte,
   damit sie mit ihr wachsen. Das Original ist 275 x 258 px, also leicht
   liegend; hier steht bewusst ein Quadrat. Es ist etwas größer als das
   Original, damit an den runden Ecken nicht hervorblitzt, was darunter liegt. */
.ubahn {
    position: absolute;
    width: 3.844%;
    aspect-ratio: 1;
    background: #312783;
    border-radius: calc(var(--map-w, 60rem) * 0.0028);
    display: grid;
    place-items: center;
    z-index: 6;
    cursor: pointer;
}

.ubahn--start { left: 18.002%; top: 2.681%; }
.ubahn--ost   { left: 91.540%; top: 68.132%; }

.ubahn-zeichen {
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
    font-size: calc(var(--map-w, 60rem) * 0.03);
    line-height: 1;
    color: #fff;
    /* Die Versalie sitzt in ihrer Zeile tiefer als in deren Mitte. Ohne
       diesen Ausgleich stünde das U sichtbar zu weit unten im Kasten. */
    transform: translateY(-3.1%);
    pointer-events: none;
}


/* ====================[[[  Startzeiger  ]]]==================== */


/* Die Spitze des Pfeils sitzt auf 0/0 seines viewBox. Die linke obere Ecke
   dieses Kastens ist damit die Spitze — sie steht schräg unter dem U-Bahn-
   Zeichen und zeigt darauf. Alle Maße hängen an der Kartenbreite, damit der
   Zeiger mit der Karte wächst. */
.startzeiger {
    position: absolute;
    /* Die Spitze des Pfeils liegt in der linken oberen Ecke dieses Kastens,
       seine Achse zeigt 34,7 Grad nach oben links. Diese beiden Werte setzen
       die Spitze auf die Verlängerung genau durch die Mitte des U-Bahn-
       Zeichens, kurz vor dessen Kante. Bei anderer Breite bleiben sie gültig. */
    left: 22.34%;
    top: 8.07%;
    width: 8%;
    z-index: 6;
    opacity: 0;
    animation: zeiger-auf 0.6s 0.5s ease-out forwards;
    pointer-events: none;
}

.startzeiger-pfeil {
    display: block;
    width: 100%;
    height: auto;
    fill: var(--yellow);
}

/* Sitzt am hinteren Ende des Pfeils, rechts unten */
.startzeiger-wort {
    position: absolute;
    /* Die Mitte des Pfeilendes liegt bei 92,1 % / 84,8 % des Kastens —
       das Wort steht rechts daneben, auf gleicher Höhe. */
    left: 103%;
    top: 92.84%;
    translate: 0 -50%;
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
    font-size: calc(var(--map-w, 60rem) * 0.04);
    line-height: 1;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--yellow);
    white-space: nowrap;
}

@keyframes zeiger-auf {
    to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .startzeiger { animation-duration: 0.01s; animation-delay: 0s; }
}


/* ====================[[[  Haltestellenname  ]]]==================== */


/* Name und Pfeil erscheinen zusammen beim Hovern. Sie stehen seitlich neben
   dem Zeichen, nicht darunter: Unter dem östlichen Zeichen wären sie von der
   Rahmenkante abgeschnitten. */
.ubahn-name,
.ubahn-pfeil {
    position: absolute;
    top: 50%;
    translate: 0 -50%;
    opacity: 0;
    transition: opacity 0.25s ease;
    pointer-events: none;
}

.ubahn-name {
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
    font-size: calc(var(--map-w, 60rem) * 0.0145);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--yellow-bright);
    white-space: nowrap;
}

/* Kleines Dreieck, das vom Namen auf das Zeichen zeigt */
.ubahn-pfeil {
    width: 0;
    height: 0;
    border-top: calc(var(--map-w, 60rem) * 0.005) solid transparent;
    border-bottom: calc(var(--map-w, 60rem) * 0.005) solid transparent;
}

.ubahn--start .ubahn-name  { left: 140%; }
.ubahn--start .ubahn-pfeil {
    left: 112%;
    border-right: calc(var(--map-w, 60rem) * 0.0068) solid var(--yellow-bright);
}

.ubahn--ost .ubahn-name  { right: 140%; }
.ubahn--ost .ubahn-pfeil {
    right: 112%;
    border-left: calc(var(--map-w, 60rem) * 0.0068) solid var(--yellow-bright);
}

.ubahn:hover .ubahn-name,
.ubahn:hover .ubahn-pfeil,
.ubahn:focus-visible .ubahn-name,
.ubahn:focus-visible .ubahn-pfeil {
    opacity: 1;
}


/* ====================[[[  Pin-Card  ]]]==================== */


.pin-card {
    position: absolute;
    z-index: 10;
    width: var(--card-width);
    padding: 0.85rem 0.95rem 1rem;
    background: var(--yellow);
    opacity: 0;
    transform: translateY(0.4rem);
    transition: opacity 0.25s ease, transform 0.25s ease;
    pointer-events: none;
}

.pin-card.is-visible {
    opacity: 1;
    transform: translateY(0);
}

.pin-card-media {
    display: grid;
    place-items: center;
    aspect-ratio: 4 / 3;
    margin-bottom: 0.7rem;
    background: var(--red);
    font-family: "dml", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-size: 0.8rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--yellow);
}

.pin-card-index {
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
    font-size: 0.8rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--red);
    margin-bottom: 0.2rem;
}

.pin-card-title {
    color: var(--red);
    margin-bottom: 0.3rem;
}

.pin-card-place {
    font-size: 0.85rem;
    line-height: 1.35;
    color: var(--red);
}


/* Nur aktiv über index.html?pins — Hilfe zum Ablesen von Koordinaten */
.pin-picker {
    position: absolute;
    top: 1.5rem;
    left: 1.5rem;
    z-index: 20;
    padding: 0.4rem 0.7rem;
    background: var(--yellow-bright);
    font-family: "dml", monospace;
    font-size: 0.85rem;
    color: var(--red);
}


/* __________________________________________________________________________________ */
/* ________________________________[[[  Intro  ]]]___________________________________ */
/* __________________________________________________________________________________ */


/* Ohne feste Höhe: so hoch wie der Inhalt. Dadurch steht der Text auf großen
   Schirmen unten statt mittig in einer leeren Fläche, und die Fußzeile sitzt
   am unteren Seitenende.

   Der Aufbau ist derselbe wie auf den Unterseiten — Rubrik, Plakattitel,
   asymmetrisches Raster mit Angabenspalte. Die Bausteine dafür kommen aus
   pages.css, hier stehen nur die Abweichungen: kein Farbband, weil der Text
   über der Karte liegt, und ein etwas kleinerer Titel. */
#intro {
    position: relative;
    z-index: 2;
    display: flex;
    justify-content: center;
    padding: clamp(2rem, 5vh, 3.5rem) clamp(1.5rem, 5vw, 4rem) clamp(2rem, 4.5vh, 3rem);

    /* Am Ende ausgerichtet: Der Anfang der Sektion liegt weiter unten als
       überhaupt gescrollt werden kann, das Ende ist der erreichbare Punkt. */
    scroll-snap-align: end;
}

.intro-inner {
    width: 100%;
    max-width: 68rem; /* dasselbe Maß wie die Bänder der Unterseiten */
}

/* Kleiner als auf den Unterseiten: Der Titel liegt hier über der Karte und
   soll sie nicht zudecken. */
.intro-title {
    font-size: clamp(1.9rem, 4vw, 3.4rem);
    margin-bottom: clamp(1.5rem, 3.5vh, 2.5rem);
}

.intro-split {
    align-items: start;
}

/* Zeilenmaß in ch hält den Fließtext bei rund 62 Zeichen. Trennung, weil
   deutsche Komposita sonst löchrige Ränder erzeugen. */
.intro-text {
    max-width: 62ch;
    font-size: clamp(0.98rem, 1.1vw, 1.1rem);
    line-height: 1.55;
    text-wrap: pretty;
    hyphens: auto;
}

.intro-link {
    display: inline-block;
    margin-top: clamp(1.1rem, 2.2vh, 1.6rem);
    font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
    font-weight: 700;
    font-size: clamp(1rem, 1.2vw, 1.2rem);
    color: var(--yellow-bright);
    cursor: pointer;
    padding-bottom: 0.2em;
    border-bottom: 3px solid var(--yellow-bright);
    transition: color 0.25s ease, border-color 0.25s ease;
}

.intro-link:hover {
    color: var(--offwhite);
    border-color: var(--offwhite);
}

.footer-inner {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    width: 100%;
    margin-top: clamp(1.4rem, 3.2vh, 2.4rem);
    padding-top: clamp(0.8rem, 1.7vh, 1.2rem);
    border-top: 2px dotted var(--yellow);
}

.footer-note {
    max-width: 60ch;
    font-size: 0.82rem;
    line-height: 1.55;
    color: var(--yellow);
}

.footer-links {
    display: flex;
    gap: 1.5rem;
    margin-top: 0.3rem;
    list-style: none;
    padding: 0;
}

.footer-links a {
    font-size: 0.85rem;
    color: var(--yellow-bright);
    cursor: pointer;
    border-bottom: 1px solid transparent;
    transition: border-color 0.25s ease;
}

.footer-links a:hover {
    border-color: var(--yellow-bright);
}


/* ====================[[[  Prüfhilfe  ]]]==================== */


/* VORÜBERGEHEND. Markiert jeden Inhaltstext, der nicht im Inhaltsdokument
   steht — also von mir formuliert oder aus dem gedruckten Flyer übernommen.
   Nicht markiert sind Schaltflächen, Menü, Weiter-Navigation und die
   Angabenspalte.

   Ändert ausschließlich die Textfarbe: kein Hintergrund, keine Polsterung,
   keine Breite — sonst verschiebt die Prüfhilfe das Layout.

   Zum Entfernen: diese Regel löschen und die Klasse "nicht-im-dokument"
   aus dem HTML nehmen. */
html:not(.lang-en) .nicht-im-dokument,
html:not(.lang-en) .nicht-im-dokument strong,
html:not(.lang-en) .nicht-im-dokument em,
html:not(.lang-en) .nicht-im-dokument a,
html:not(.lang-en) .nicht-im-dokument::before {
    color: #4ADE80;
}


/* Selbst übersetzt — im Dokument gibt es dafür keine englische Fassung.
   Wie beim Grün nur die Textfarbe, damit nichts verrutscht. */
.selbst-uebersetzt,
.selbst-uebersetzt strong,
.selbst-uebersetzt em,
.selbst-uebersetzt a,
.selbst-uebersetzt::before {
    color: #FF9ECF;
}


/* __________________________________________________________________________________ */
/* ______________________________[[[  Breakpoint  ]]]________________________________ */
/* __________________________________________________________________________________ */


/* Der einzige Breakpoint in dieser Datei. Alles zum Klappmenü steht hier
   drin und nirgends sonst — oberhalb existiert weder Knopf noch Feld für den
   Browser, und an der bestehenden Seite ändert sich dadurch nichts.

   68rem und nicht 52rem, weil die Kopfzeile eher an ihre Grenze kommt als der
   Inhalt: Wortmarke und Menü berühren sich bei 860 px und werden darunter
   zusammengestaucht. Bei 1088 px liegen noch 175 px dazwischen, das Zehnfache
   des Abstands innerhalb des Menüs — vorher wirken die beiden Blöcke wie ein
   einziger. Die Spalten der Unterseiten klappen weiterhin erst bei 52rem um,
   ihr Platzbedarf ist ein anderer; das steht in pages.css.

   Der Knopf steht im HTML auf hidden; erst die Regel hier holt ihn hervor.
   Das Feld bleibt geschlossen unsichtbar, weil display nur für [open] gesetzt
   wird — sonst überschriebe es die Browserregel für geschlossene Dialoge. */
@media (max-width: 68rem) {

    .main-nav {
        display: none;
    }

    /* Umrandetes Quadrat wie die Sprachwahl und die U-Bahn-Zeichen.
       Die Maße in Pixeln, weil das Kreuz daraus entsteht, dass die äußeren
       Balken um Abstand plus Balkenhöhe einrücken: 5 + 2 = 7 px. In rem
       ginge das nicht glatt auf und die Striche kreuzten sich versetzt. */
    .menue-knopf {
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        gap: 5px;
        width: 44px;
        height: 44px;
        background: none;
        outline: 2px solid var(--yellow-bright);
        outline-offset: 0;
        margin-right: -0.5rem; /* der Rahmen bündig zum Seitenrand */
    }

    .menue-knopf span {
        display: block;
        width: 22px;
        height: 2px;
        background: var(--yellow-bright);
        /* translate und rotate getrennt, damit sie nacheinander laufen:
           erst rücken die Balken zusammen, dann drehen sie sich. Beides
           gleichzeitig sieht nach Zappeln aus. */
        transition: translate 0.18s ease 0.18s,
                    rotate 0.18s ease,
                    opacity 0.15s ease 0.18s;
    }

    .menue-knopf--zu span {
        transition: translate 0.18s ease,
                    rotate 0.18s ease 0.18s,
                    opacity 0.12s ease;
    }

    .menue-knopf--zu span:nth-child(1) { translate: 0 7px;  rotate: 45deg; }
    .menue-knopf--zu span:nth-child(2) { opacity: 0; }
    .menue-knopf--zu span:nth-child(3) { translate: 0 -7px; rotate: -45deg; }

    /* Das Feld liegt in der obersten Ebene des Browsers, deshalb braucht es
       weder z-index noch einen Platz außerhalb der Hero. */
    .menue[open] {
        display: flex;
        flex-direction: column;
    }

    .menue {
        width: 100%;
        max-width: none;

        /* dvh, nicht 100 % — und das ist der Unterschied zwischen „passt"
           und „passt nicht". Ein modales <dialog> liegt in der obersten
           Ebene, seine 100 % rechnen deshalb gegen den Layout-Viewport, und
           der ist auf iOS so hoch, als wären die Safari-Leisten eingefahren.
           Das Feld wurde dadurch rund 90 px höher als der sichtbare Bereich,
           sein unteres Ende lag hinter der Leiste — und weil es damit nie
           überlief, rollte auch nichts. Mit dvh ist es genau so hoch wie das,
           was gerade zu sehen ist, und der Inhalt rollt in sich. */
        height: 100dvh;
        max-height: none;
        margin: 0;
        padding: 0;
        border: 0;
        background: var(--grey);
        color: var(--yellow-bright);
        overflow: hidden;
        animation: menue-auf 0.22s ease-out;
    }

    .menue::backdrop {
        background: rgba(32, 59, 115, 0.75);
    }

    .menue:focus {
        outline: none;
    }

    @keyframes menue-auf {
        from { opacity: 0; }
        to   { opacity: 1; }
    }

    /* Dieselben Abstände wie die Kopfzeile darunter, damit der Knopf beim
       Öffnen genau an seiner Stelle stehen bleibt. */
    .menue-zeile {
        flex: 0 0 auto;
        display: flex;
        justify-content: flex-end;
        padding: clamp(0.75rem, 1.1vw, 1rem) clamp(1rem, 2.5vw, 2.5rem) clamp(0.4rem, 0.6vw, 0.5rem);
    }

    /* Scrollt für sich, falls die Liste länger wird als der Schirm */
    .menue-inhalt {
        flex: 1 1 auto;
        padding: 0.5rem clamp(1.5rem, 6vw, 2.5rem) 2rem;
        overflow-y: auto;
        overscroll-behavior: contain;
    }

    .menue-inhalt .nav-list {
        flex-direction: column;
        align-items: stretch;
        gap: 0;
    }

    .menue-inhalt .nav-list > li > a,
    .menue-inhalt .submenu-trigger {
        display: flex;
        align-items: center;
        min-height: 2.75rem;   /* 44 px, Untergrenze für eine Daumenfläche */
        font-size: 1.05rem;
    }

    /* Der mitlaufende Unterstrich ist für den Zeiger gedacht — getippt wird,
       nicht gezielt. */
    .menue-inhalt .nav-list a::after,
    .menue-inhalt .submenu-trigger::after {
        display: none;
    }

    /* Das Untermenü steht offen da. Ein zweiter Tipp, nur um an die Projekte
       zu kommen, wäre ein Umweg ohne Gewinn. Die gepunktete Linie ist
       dieselbe wie die Wegführung auf der Karte. */
    .menue-inhalt .has-submenu {
        position: static;
    }

    .menue-inhalt .submenu {
        position: static;
        gap: 0;
        margin: 0 0 0.5rem;
        padding: 0 0 0 0.9rem;
        background: none;
        opacity: 1;
        visibility: visible;
        transform: none;
        white-space: normal;
        border-left: 2px dotted var(--yellow);
    }

    .menue-inhalt .submenu a {
        display: flex;
        align-items: center;
        min-height: 2.75rem;   /* 44 px, wie die Ebene darüber */
        padding: 0.2rem 0;
        white-space: normal;
        font-size: 0.86rem;
        line-height: 1.25;
    }

    .menue-inhalt .nav-lang {
        margin-top: 1.25rem;
    }

    .menue-inhalt .lang-option {
        display: flex;
        align-items: center;
        min-height: 2.5rem;
        padding: 0 1.1em;
        font-size: 0.95rem;
    }

    /* Tastaturbedienung in der Farbe der Seite statt im Blau des Browsers */
    .menue a:focus-visible,
    .menue button:focus-visible {
        outline: 2px solid var(--offwhite);
        outline-offset: 3px;
    }

    @media (prefers-reduced-motion: reduce) {
        .menue { animation: none; }
        .menue-knopf span,
        .menue-knopf--zu span { transition-duration: 0.01s; transition-delay: 0s; }
    }
}


/* __________________________________________________________________________________ */
/* _____________________________[[[  Hochformat  ]]]_________________________________ */
/* __________________________________________________________________________________ */


/* Zweiter Breakpoint, diesmal nicht auf die Breite, sondern auf das
   Seitenverhältnis: Sobald das Fenster höher als breit ist, steht unter
   der Karte die Projektliste. Der
   Grund ist ein anderer als beim Klappmenü — dort geht es um die Kopfzeile,
   hier darum, dass die Punkte auf der Karte bei dieser Form zu dicht
   beieinanderliegen, um sie mit dem Daumen einzeln zu treffen.

   Die Knöpfe sind im Vokabular der Seite gehalten: rechtwinklig, gelbe
   Fläche, blaue Schrift, ohne Schatten und ohne Rundung — wie das aktive
   Feld der Sprachwahl. Der angefasste Zustand geht auf das helle Gelb.
   Beides folgt der Datenbank: Zustände über Farbe statt über Erhebung,
   0 px Radius, keine Schatten. */
@media (max-aspect-ratio: 1 / 1) {

    /* Feste Höhe statt mitwachsend. Beides flexibel führte dazu, dass die
       Liste ihren Inhalt behielt und die Karte auf 90 px zusammengedrückt
       wurde — sie hat keine eigene Inhaltshöhe, alles darin liegt absolut. */
    .map-container {
        flex: 0 0 auto;

        /* Drei Deckel, der engste gilt.

           80vw sind dieselben 5:4 wie die Deckelung darüber.
           58svh fangen das Querformat ab, wo 80vw ein Vielfaches der
           Fensterhöhe wären.
           Der dritte hält der Liste ihren Platz frei: zwei Spalten, also
           fünf Reihen Knöpfe plus Scroll-Anzeiger, Kopfzeile und Abstände —
           zusammen 30rem. Dadurch stehen immer alle zehn Knöpfe im Bild,
           statt dass die Liste rollen müsste.
           Zwei Spalten brauchen nur die Hälfte; dafür steht weiter unten
           ein eigener Wert.

           Der max() darunter ist die Notbremse für kurze Telefone: Unter
           20svh wird die Karte nicht mehr kleiner, dann rollt eben die
           Liste. Ab etwa 800 px Fensterhöhe greift er nie. */
        height: min(80vw, 58svh, max(100svh - 30rem, 20svh));
    }

    /* Immer zwei Spalten. Eine ginge bei zehn Knöpfen nicht mehr auf: Zehn
       Reihen sind höher als jedes Telefon im Hochformat hergibt, die letzte
       Reihe fiele heraus. Mehr als zwei nie — bei drei und mehr geht die
       Reihe mit zehn Knöpfen nicht auf und die letzte bliebe angebrochen. */
    .projektliste {
        position: relative;
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 0.5rem;
        column-gap: 0.5rem;
        align-content: start;

        flex: 1 1 auto;
        min-height: 0;

        /* Rollt bewusst nicht. Alle zehn Knöpfe passen in jeder Fensterform
           gleichzeitig ins Bild — dafür sind die Reserven in der Kartenhöhe
           gerechnet. Wäre die Reihe rollbar, finge ein Wisch darüber sie ab,
           statt das Intro hochzuziehen. */
        overflow: hidden;

        /* Gleiche Flucht wie der Kartenrahmen: --map-inset ist der Abstand,
           den layoutMap() für die linke Rahmenkante ausrechnet. Die Knöpfe
           stehen damit weder näher am Rand noch weiter innen als die Karte. */
        padding: 0.6rem var(--map-inset, 1rem);

        /* Derselbe Weichzeichner wie auf der Karte. Den Wert setzt
           initIntroOverlay() an die Hero-Sektion, beide lesen ihn von dort. */
    }

    .weichzeichnen .projektliste {
        filter: blur(var(--map-blur, 0px));
    }

    /* Gefüllte Karten statt umrandeter: Das ist dasselbe Mittel wie beim
       aktiven Feld der Sprachwahl und spart die Luft, die ein Rahmen innen
       braucht. Der aktive Zustand geht auf das helle Gelb — genau der
       Wechsel, den auch die Punkte auf der Karte machen. */
    .projekt {
        /* Gitter statt Spalte, damit Nummer und „Zum Projekt" in dieselbe
           Zelle fallen. Der Knopf ist dadurch immer so breit und so hoch wie
           der längere der beiden Texte und springt beim Überfahren nicht —
           getauscht wird nur die Sichtbarkeit. */
        display: grid;
        grid-template-columns: 1fr;
        place-items: center;

        /* 44 px ist die Untergrenze für eine Fläche, die mit dem Daumen
           getroffen werden soll — siehe Datenbank. Die Zeile allein käme mit
           ihren Innenrändern auf rund 40. */
        min-height: 2.75rem;

        padding: 0.5rem 0.6rem;

        /* Derselbe Schalter wie die Sprachwahl: Im Ruhezustand nur ein
           gelber Rahmen auf dem Blau der Seite, angefasst kippt er in die
           gefüllte Fassung. Zustände über Farbe statt über Erhebung, siehe
           Datenbank. Der Rahmen liegt als inset-Schatten innen, nicht als
           border oder outline — so ändert sich an den Maßen des Knopfes
           nichts und die Reihe bleibt auf ihrer Flucht. */
        background: none;
        box-shadow: inset 0 0 0 2px var(--yellow-bright);
        cursor: pointer;
        transition: background-color 0.2s ease, color 0.2s ease;
    }

    .projekt:hover,
    .projekt.is-active {
        background: var(--yellow-bright);
    }

    /* Zwei Farben pro Knopf, nicht drei — Rot bleibt der Infokarte auf der
       Map vorbehalten. Die Schrift wechselt mit dem Grund: gelb auf Blau im
       Ruhezustand (6,4:1), blau auf Gelb im angefassten (ebenfalls 6,4:1).
       Ort und „Zum Projekt" liegen in derselben Zelle übereinander und
       tragen denselben Schnitt — so ändert der Wechsel weder Höhe noch
       Breite. */
    .projekt-ort,
    .projekt-ziel {
        grid-area: 1 / 1;
        font-family: "dml-bold", "Helvetica Neue", Helvetica, Arial, sans-serif;
        font-weight: 700;
        font-size: 1rem;      /* nie unter 16 px, siehe Datenbank */
        line-height: 1.2;
        white-space: nowrap;  /* eine Zeile, unter allen Umständen */
        overflow: hidden;
        text-overflow: ellipsis;
        color: var(--yellow-bright);
        transition: color 0.2s ease;
    }

    .projekt:hover .projekt-ort,
    .projekt:hover .projekt-ziel,
    .projekt.is-active .projekt-ort,
    .projekt.is-active .projekt-ziel {
        color: var(--blue);
    }

    .projekt-ziel {
        visibility: hidden;
    }

    .projekt.is-active .projekt-ort {
        visibility: hidden;
    }

    .projekt.is-active .projekt-ziel {
        visibility: visible;
    }
}


/* Ab 34rem ist Platz für zwei Spalten. Acht Knöpfe ergeben dann vier volle
   Reihen statt acht — die Liste braucht nur noch halb so viel Höhe, deshalb
   steht hier auch die zweite, kleinere Reserve für die Kartenhöhe.
   Getrennt werden die Spalten allein durch den Abstand; eine Linie dazwischen
   war eine Kante zu viel. */
@media (max-aspect-ratio: 1 / 1) and (min-width: 34rem) {

    .map-container {
        height: min(80vw, 58svh, 100svh - 31.25rem);
    }

    .projektliste {
        grid-template-columns: 1fr 1fr;
    }
}


/* Am Telefon fällt die Infokarte weg. Sie deckte dort die halbe Karte zu,
   und ihre Aufgabe erledigt inzwischen die Knopfreihe darunter: Welches
   Projekt gemeint ist, steht im Knopf, wo es liegt, zeigt der Punkt.
   Hidden und display stehen beide auf der Karte — hier gewinnt die Regel
   am Dateiende, showCard() kann sie nicht mehr aufdecken.

   Dafür muss der Punkt deutlicher antworten, denn er ist jetzt die einzige
   Rückmeldung auf der Karte. Das Wachsen ist verdoppelt: aus 75 Prozent
   mehr werden 150, aus dem 1,75-fachen also das 2,5-fache. */
@media (max-aspect-ratio: 1 / 1) and (max-width: 34rem) {

    .pin-card {
        display: none;
    }

    .pin {
        --wuchs: 2.5;
    }
}


/* Alles, was das Intro flacher macht. Die Grenze ist 52rem, derselbe
   Breakpoint, den auch pages.css benutzt — auf schmalen Fenstern *und* auf
   Tablets hat es sonst mehr Höhe als der Schirm.

   Zuerst die Trägerzeile: Sie läuft hier über drei bis vier Zeilen und
   drückt die Fußzeile aus dem Bild. Dieselbe Angabe steht im Impressum,
   der Weg dorthin bleibt gleich darunter stehen. Bewusst auf #intro
   begrenzt — auf den Unterseiten ist die Zeile die einzige Trägerangabe
   und bleibt. */
@media (max-width: 52rem) {

    #intro .footer-note {
        display: none;
    }


    /* Das Intro ist am Ende ausgerichtet, sein Inhalt wächst also nach oben.
       Je weniger Höhe er braucht, desto mehr Karte bleibt darüber stehen.
       Gespart wird ausschließlich an den Abständen — nicht am Fließtext: Dessen Zeilenabstand bleibt bei
       1,5, der Untergrenze, die die Datenbank für Lesetext nennt. Alles
       hier ist auf #intro begrenzt, die Unterseiten bleiben, wie sie sind. */

    /* Unten war Luft, die nichts trägt — die Fußzeile ist der letzte Inhalt.
       Oben bleibt der Abstand, dort soll ja gerade Platz entstehen. */
    #intro {
        padding-bottom: 1.25rem;
    }

    #intro .page-kicker {
        margin-bottom: 0.6rem;
    }

    /* Als clamp statt fester Wert: Am Telefon die 1,7rem, auf dem Tablet
       darf der Titel wachsen — dort ist die Höhe weniger knapp als die
       Wirkung des Plakattitels. */
    #intro .intro-title {
        font-size: clamp(1.7rem, 3.6vw, 2.4rem);
        margin-bottom: 0.9rem;
    }

    #intro .intro-text {
        line-height: 1.5;
    }

    #intro .intro-link {
        margin-top: 0.9rem;
    }

    #intro .intro-split {
        gap: 1.25rem;
    }

    /* Rubrik über dem Wert, wie überall sonst auf der Seite. Nebeneinander
       war zwar halb so hoch, aber die lange Rubrik brach dabei um und die
       Spalte franste aus. Gespart wird hier nur am Abstand zwischen den
       vier Angaben. */
    #intro .meta-row + .meta-row {
        margin-top: 0.6rem;
    }

    #intro .footer-inner {
        margin-top: 1rem;
        padding-top: 0.6rem;
    }
}


/* ====================[[[  Kleine Telefone  ]]]==================== */


/* Bis 28rem — jedes Telefon im Hochformat, kein Tablet. Hier ist die Höhe
   das knappe Gut, und sie ging bisher an die Abstände und an die Knopfreihe
   statt an die Karte: Auf einem iPhone blieben dem Kartenrahmen 144 px,
   obwohl das Bild bei dieser Breite 229 px hoch sein darf. Also alles enger
   außer der Karte selbst.

   Nicht angetastet: die Schriftgrößen im Fließtext und auf den Knöpfen
   (16 px ist die Untergrenze der Datenbank), die 44 px Höhe der Knöpfe und
   des Klappmenü-Knopfs (Untergrenze für eine Daumenfläche) und die 8 px
   Abstand dazwischen (Untergrenze für benachbarte Trefferflächen). Der
   Streifen für den Scroll-Anzeiger schrumpft dagegen von 96 auf 48 px — er
   trägt eine einzige Zeile. */
@media (max-width: 28rem) {


    #hero {
        row-gap: 0.75rem;     /* statt 25 px */
        padding-bottom: 3rem; /* statt 6 rem */

        /* Warum vom Intro schon etwas zu sehen ist, bevor man wischt:
           100svh ist die Höhe mit ausgefahrenen Leisten — auf dem iPhone rund
           670 px. Safari zeichnet die Seite aber bis an die Unterkante des
           Schirms, also auch in den Streifen um die schwebende untere Leiste
           herum, und der ist noch einmal rund 80 px hoch. Die Hero endet bei
           670, dort beginnt das Intro, und seine ersten Zeilen landen genau
           in diesem Streifen.

           Der Abstand darunter ist exakt dieser Überhang: die große
           Viewport-Höhe minus der kleinen. Auf dem Rechner sind beide gleich,
           die Rechnung ergibt dort 0 und nichts ändert sich. Auf dem Telefon
           schiebt sie das Intro hinter die Leiste, und im Streifen steht nur
           noch das Blau der Seite. Die Hero selbst bleibt 100svh hoch, der
           Scroll-Anzeiger also sichtbar — 100lvh hätte ihn mit verdeckt. */
        margin-bottom: calc(100lvh - 100svh);
    }

    #header {
        padding: 0.4rem 1rem 0.3rem;
    }

    .projektliste {
        padding-block: 0.4rem;
    }

    /* Enger als sonst, damit „Baakenhafen West" auch in eine halbe Breite
       passt — siehe die zweite Spalte weiter unten. */
    .projekt {
        padding-inline: 0.4rem;
    }

    /* 25rem sind fünf Reihen zu 44 px, vier Abstände zu 8 px, die Ränder
       der Liste, die Kopfzeile und der Streifen für den Scroll-Anzeiger. */
    .map-container {
        height: min(80vw, 58svh, max(100svh - 25rem, 20svh));
    }

    .scroll-cue {
        bottom: 0.9rem;
    }
}


/* Schmal *und* niedrig — hier stehen die Knöpfe nebeneinander. Untereinander
   brauchen acht zu 44 px 421 px Höhe, und die gehen der Karte ab.
   Nachgerechnet für ein iPhone mit 390 px Breite und rund 670 px sichtbarer
   Höhe:

       1 Spalte:  Liste 421 px, für die Karte bleiben 164 →
                  Rahmen 144 px von 229 möglichen
       2 Spalten: Liste 213 px, für die Karte bleiben 372 →
                  Rahmen 229 px, also die volle Höhe

   Die Grenze steht bewusst hoch, bei 60rem statt bei den 50rem, ab denen es
   rechnerisch reicht: Media Queries lesen auf iOS die Fensterhöhe so, als
   wären die Safari-Leisten eingefahren — ein Telefon, von dem nur 670 px zu
   sehen sind, meldet hier 844. Bei 60rem fällt jedes Telefon im Hochformat
   in diese Regel, ein schmales, aber hohes Fenster am Rechner dagegen nicht.

   Die Reserve für die Karte halbiert sich mit: 21rem sind vier Reihen statt
   acht. */
@media (max-width: 28rem) and (max-height: 60rem) {

    .projektliste {
        grid-template-columns: 1fr 1fr;
    }

    .map-container {
        height: min(80vw, 58svh, max(100svh - 25rem, 20svh));
    }
}


/* ====================[[[  Kleine Bildschirme: Text  ]]]==================== */


/* Bis 29rem breit *und* 63rem hoch — rund ein Fünftel über den Maßen eines
   iPhone im Hochformat (390 × 844, so meldet es sich einer Media Query).
   Ein schmales, aber hohes Fenster am Rechner fällt nicht darunter, dort ist
   Höhe genug und der Text darf luftig bleiben.

   Hier wird beides enger: die Abstände und die Schrift. Der Fließtext geht
   dabei auf 15,2 px herunter. Das ist knapp unter den 16 px, die die
   Datenbank als Untergrenze für Lesetext nennt — bewusst und auf Ansage, und
   bewusst nur um diesen einen Schritt: Der Zeilenabstand bleibt bei 1,5, und
   alles andere kommt aus den Abständen, nicht aus der Schriftgröße. */
@media (max-width: 29rem) and (max-height: 63rem) {

    /* Die Kopfzeile tritt ab, sobald das Intro hochkommt. Sie sitzt in der
       klebenden Hero und bliebe sonst über dem Intro stehen — auf dem Telefon
       mitten im Titel, und sie wandert dabei mit dem Text mit. Dieselbe
       Schwelle wie beim Scroll-Anzeiger; die Klasse setzt initIntroOverlay().
       Auf breiten Schirmen bleibt die Kopfzeile stehen, dort ist Platz. */
    #header {
        transition: opacity 0.25s ease;
    }

    #hero.intro-kommt #header {
        opacity: 0;
        pointer-events: none;
    }

    #intro {
        padding-top: 1.25rem;
        padding-bottom: 1rem;
    }

    #intro .page-kicker {
        font-size: 0.72rem;
        margin-bottom: 0.4rem;
    }

    #intro .intro-title {
        font-size: 1.45rem;
        margin-bottom: 0.7rem;
    }

    #intro .intro-text {
        font-size: 0.95rem;
        line-height: 1.5;
    }

    #intro .intro-link {
        margin-top: 0.7rem;
        font-size: 0.95rem;
    }

    #intro .intro-split {
        gap: 0.9rem;
    }

    #intro .meta-label {
        font-size: 0.66rem;
        margin-bottom: 0.15rem;
    }

    #intro .meta-value {
        font-size: 0.86rem;
    }

    #intro .meta-row + .meta-row {
        margin-top: 0.4rem;
    }

    #intro .footer-inner {
        margin-top: 0.7rem;
        padding-top: 0.4rem;
    }

    #intro .footer-links {
        margin-top: 0.15rem;
    }

    #intro .footer-links a {
        font-size: 0.8rem;
    }


    /* Das Klappmenü gleich mit, und hier auch an den Zeilenhöhen: Fünfzehn
       Einträge zu 44 px sind allein 660 px, mehr als auf einem Telefon zu
       sehen ist — die Liste musste deshalb immer rollen. 37,6 px in der
       ersten Ebene und 33,6 px im Untermenü sind unter den 44 px, die die
       Datenbank für eine Daumenfläche nennt; das ist wie bei der Schrift
       eine bewusste Entscheidung auf Ansage. Die Einträge sind dafür
       vollbreit und stehen untereinander, danebengreifen kann man kaum. */
    .menue-zeile {
        padding: 0.4rem 1rem 0.3rem;
    }

    .menue-inhalt {
        padding: 0.25rem 1.25rem 1rem;
    }

    .menue-inhalt .nav-list > li > a,
    .menue-inhalt .submenu-trigger {
        min-height: 2.35rem;
        font-size: 0.95rem;
    }

    .menue-inhalt .submenu {
        margin-bottom: 0.3rem;
    }

    .menue-inhalt .submenu a {
        min-height: 2.1rem;
        padding: 0.1rem 0;
        font-size: 0.8rem;
    }

    .menue-inhalt .nav-lang {
        margin-top: 0.6rem;
    }

    .menue-inhalt .lang-option {
        min-height: 2.35rem;
    }
}
