/* Hallmark · checked: 2026-11-03 · genre: editorial (inferred) · job: enquire
 * fixed: 6a 7a 15 26a 34 39a 40 48 67 F6 · structural: printed (44c 58 59 77 78 85)
 * built: the project · redesign: polish · v2.0.0 */
/* Hallmark · dismissed 62 · .np-reveal und .np-van--bereit setzt erst das Skript (main.js, delivery-van.php); ohne JavaScript ist alles sichtbar */
/* ==================================================================
   nextparty24 - Stylesheet
   ==================================================================

   Aufbau, von oben nach unten:

     1. Schriften        selbst gehostet, keine Anfrage nach draussen
     2. Tokens           Farben, Abstaende, Radien, Schatten
     3. Grundlagen       Reset, Typografie, Fokus
     4. Bausteine        Knopf, Karte, Etikett, Formularfeld, Segment
     5. Effekte          Aurora, Grain, Scroll-Reveals
     6. Rahmen           Kopf, Navigation, Fuss
     7. Seiten           Start, Katalog, Artikel, Pakete, Anfrage, Info
     8. Umbrueche        alles Responsive gebuendelt am Ende

   Grundlage ist der Design-Prototyp (Design.md). Die Klassennamen aus dem
   Prototyp (.np-*) sind uebernommen, damit die Spec lesbar bleibt.

   Zwei Regeln, die das Bild tragen:
     - Zwei Akzente: Neongelb traegt, Cyan antwortet. Gelb darf Flaeche
       sein (Knopf, Marke, Kante), aber nur an wenigen Stellen - Preise
       und Fliesstext bleiben weiss. Seit dem 15.09.2026 - vorher war der
       Akzent nur Umriss, und genau das sah aus wie jede andere dunkle
       Seite mit KI-Handschrift.
     - Ueberschriften tragen ueber ihr Gewicht (800), nicht nur ueber die
       Groesse.
   ================================================================== */


/* ==================================================================
   1. Schriften
   ================================================================== */

/* Plus Jakarta Sans - Variable Font, deckt 400 bis 800 aus einer Datei. Text in 400,
   Hervorhebungen 600, Ueberschriften 800: die Ueberschrift traegt durch
   ihr Gewicht, nicht nur durch die Groesse. Quelle: Google Fonts, SIL OFL,
   selbst gehostet. */
@font-face {
    font-family: "Plus Jakarta Sans";
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url("../fonts/plus-jakarta-sans-latin.woff2") format("woff2");
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                   U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
                   U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: "Plus Jakarta Sans";
    font-style: normal;
    font-weight: 400 800;
    font-display: swap;
    src: url("../fonts/plus-jakarta-sans-latin-ext.woff2") format("woff2");
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
                   U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Expansiva - die Schrift der Wortmarke. Nur fuer Zahlen, Preise,
   Kicker und Stat-Werte, nie fuer Fliesstext. */
@font-face {
    font-family: "Expansiva";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("../fonts/expansiva-bold.otf") format("opentype");
}


/* ==================================================================
   2. Tokens
   ================================================================== */

:root {
    /* Gemeinsame Tokens - Farben, Schrift, Schriftgroessen, Abstaende,
       Rundungen, Linien - stehen in css/tokens.css und gelten fuer
       Webseite, Admin und Kundenbereich. Hier steht nur, was allein die
       Webseite betrifft. */

    /* Sagt dem Browser, dass die Seite dunkel ist. Datumswaehler,
       Auswahllisten und Bildlaufleisten kommen dadurch dunkel statt
       weiss auf schwarz. */
    color-scheme: dark;

    /* Die farbigen Baender zwischen den Abschnitten. Sie laufen von Gelb
       nach Cyan - das Band ist die lauteste Flaeche der Seite. */
    --color-section: #121705;
    --color-section-glow: #29330b;
    --color-section-ghost: #0e7a86;

    /* Plus Jakarta Sans 800 ist gewollt kraeftig: die Webseite will
       auffallen. Der Admin nimmt 600 (siehe admin.css). */
    --weight-heading: 800;

    /* ---------- Claymorphismus ----------
       Flaechen sehen aus wie weiche Knetmasse: eine helle Kante oben
       links, eine tiefe unten rechts, dazu ein weicher Wurf auf den Grund.
       Am 16.09.2026 zweimal abgeschwaecht - die Form ist zu ahnen, nicht
       anzufassen. Wer sie deutlicher will, dreht die Werte unten hoch;
       einzelne Bausteine haben keine eigenen Schatten. */
    --clay-licht: inset 1px 1px 2px rgba(255, 255, 255, .035);
    --clay-tiefe: inset -1px -2px 6px rgba(0, 0, 0, .22);

    --shadow-sm: var(--clay-licht), var(--clay-tiefe), 0 4px 10px -8px rgba(0, 0, 0, .5);
    --shadow-md: var(--clay-licht), var(--clay-tiefe), 0 8px 18px -12px rgba(0, 0, 0, .55);
    --shadow-lg: var(--clay-licht), var(--clay-tiefe), 0 14px 28px -16px rgba(0, 0, 0, .6);

}



/* ==================================================================
   3. Grundlagen
   ================================================================== */

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

html {
    background: var(--color-bg);
    scroll-behavior: smooth;
    overflow-x: clip;
}

body {
    /* transparent, damit die Aurora dahinter durchscheint */
    margin: 0;
    /* clip statt hidden: schneidet seitlich ab, ohne einen eigenen
       Scrollbereich anzulegen - position: sticky bleibt heil. */
    overflow-x: clip;
    background: transparent;
    color: var(--color-text);
    font-family: var(--font-body);
    font-size: var(--text-base);
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-heading);
    font-weight: var(--weight-heading);
    line-height: 1.15;
    margin: 0 0 var(--space-3);
    text-wrap: balance;
}
h1 { font-size: var(--text-h1); letter-spacing: -0.015em; }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-xl); }
h4 { font-size: var(--text-lg); }

p { margin: 0 0 var(--space-3); }
p:last-child { margin-bottom: 0; }

a {
    color: var(--color-accent);
    text-decoration: none;
    text-underline-offset: 3px;
}
a:hover { color: var(--color-accent-300); text-decoration: underline; }

/* Links, die in einer Karte eine Zeile oder eine Ueberschrift SIND,
   tragen die Textfarbe. Die Akzentfarbe ist Linie und Marke, nicht
   Flaeche und nicht Fliesstext - sonst flimmert eine Liste aus zehn
   Produktnamen. */
.card-title a,
.np-pack li a,
.np-listrow a { color: inherit; text-decoration: none; }
.card-title a:hover,
.np-pack li a:hover,
.np-listrow a:hover { color: var(--color-accent-300); text-decoration: underline; }

img, svg, video { display: block; max-width: 100%; }
figure { margin: 0; }
address { font-style: normal; }
ul, ol { margin: 0 0 var(--space-3); padding-left: 1.2em; }

/* Sprungziele hinter der fixen Kopfleiste.
   Die Leiste ist 63 px hoch und steht immer oben. Ohne diesen Abstand
   scrollt der Browser die Ueberschrift exakt an den Fensterrand - und
   damit unter die Leiste, wo sie niemand liest. Betrifft jeden Anker:
   #cookies aus dem Cookie-Hinweis, die Paragraphen der AGB, die
   Rubriken der FAQ.

   Warum 96 und nicht 66: Wer die Adresse MIT #anker aufruft, springt
   waehrend des Ladens - und der Browser rechnet dabei mit einem Layout,
   das sich danach noch minimal aendert (Schriften kommen nach). Gemessen
   waren es rund 14 px zu weit. Mit knapp Luft kaeme die Ueberschrift
   dann doch wieder an die Leiste; mit 96 bleibt auch nach der
   Verschiebung genug Abstand, und beim Sprung innerhalb der Seite steht
   sie etwas tiefer, was nicht stoert. */
h1[id], h2[id], h3[id] { scroll-margin-top: var(--space-24); }

:focus { outline: none; }
:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
    border-radius: var(--radius-sm);
}
::selection { background: color-mix(in srgb, var(--color-accent) 30%, transparent); }

/* Springt bei Tab-Bedienung als Erstes an */
.skiplink {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    padding: var(--space-3) var(--space-4);
    background: var(--color-surface);
    color: var(--color-text);
    border-radius: 0 0 var(--radius-md) 0;
}
.skiplink:focus { left: 0; }

.visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* Fotos liegen im "lighten"-Modus auf dunklem Grund: schwarze Bildanteile
   verschwinden im Hintergrund, das Bild franst aus statt als Kachel zu
   kleben. Motive mit dunklem Hintergrund bevorzugen. */
.lighten {
    mix-blend-mode: lighten;
    background-color: transparent;
}


/* ------------------------------------------------------------------
   Raster und Rhythmus
   ------------------------------------------------------------------ */

/* Wichtig: .np-wrap setzt das seitliche Gutter, .np-sec nur vertikales
   Padding. Ein Shorthand an einer der beiden Stellen wuerde das Gutter
   ueberschreiben - dann klebt der Inhalt am Rand. */
/* Seitenbreite (.np-wrap): css/bausteine.css */
.np-sec { padding-top: var(--space-16); }
.np-sec--tight { padding-top: var(--space-8); }

/* ---------- Farbiger Block ----------
   Ein Abschnitt ueber die volle Breite mit eigenem Grund. Die Seite ist
   dadurch nicht mehr durchgehend schwarz, sondern hat Rhythmus: dunkel,
   Block, dunkel. Der Inhalt bleibt im .np-wrap darin.

   Die Kante oben und unten ist eine duenne Akzentlinie - ohne sie
   schwimmt der Block im Schwarz, statt aufzuliegen. */
.np-block {
    background:
        linear-gradient(180deg,
            color-mix(in srgb, var(--color-section) 90%, transparent) 0%,
            color-mix(in srgb, var(--color-section-glow) 45%, transparent) 100%);
    border-block: 1px solid color-mix(in srgb, var(--color-accent) 14%, transparent);
    margin-block: var(--space-16);
}
.np-block > .np-sec { padding-top: var(--space-12); padding-bottom: var(--space-12); }
.np-block + .np-block { margin-top: 0; }

.np-sec-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-5);
    flex-wrap: wrap;
}
.np-sec-head h1,
.np-sec-head h2 { margin: 0; }

.np-row {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}
.np-row--wrap { flex-wrap: wrap; }
.np-row--between { justify-content: space-between; }

.np-stack {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}

/* Alle Karten- und Kachelraster teilen sich dieses Muster: nie feste
   Breiten, immer auto-fill mit Mindestbreite.

   auto-fill und nicht auto-fit: auto-fit laesst leere Spalten
   zusammenfallen - eine einzelne Kachel ginge dann ueber die ganze
   Breite, zwei je ueber die Haelfte. Mit auto-fill bleiben die leeren
   Spalten stehen, und eine Kachel ist immer so breit wie in einer vollen
   Reihe. Das ist zugleich ihre Hoechstbreite.

   Das ist nicht nur Geschmack: ein Paket oder eine Kategorie, die allein
   ueber die ganze Breite geht, sieht aus wie etwas anderer Art als
   dieselbe Kachel neben zwei weiteren. Die Groesse einer Kachel soll
   etwas ueber den Inhalt sagen und nichts darueber, wie viele gerade
   sichtbar sind (Betreiber, 12.10.2026: "es muss immer die gleiche
   Breite sein" - vorher fuellten Kategorien und Referenzen die Reihe).

   Einzige Ausnahme sind die vier Schritte (.np-grid--steps): es sind
   immer genau vier, dort fuellt auto-fit die Reihe gleichmaessig. */
.np-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: var(--space-4);
}
.np-grid--items { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }
.np-grid--packs { grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); }
.np-grid--cats  { grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--space-3); }
.np-grid--refs  { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--space-3); }
/* Auf dem Handy reichen 210 px Mindestbreite nur fuer eine Kachel je
   Zeile - jede Kategorie stand allein. Zwei feste Spalten passen dort
   gut (Betreiber, 14.10.2026); die Kachel rueckt dafuer etwas enger. */
@media (max-width: 520px) {
    .np-grid--cats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .np-grid--cats .np-cat { padding: var(--space-3); }
    .np-grid--cats .card-title { hyphens: auto; overflow-wrap: break-word; }
}
/* Die vier Schritte brauchen mehr Luft als ein gewoehnliches Raster: der
   Zeilenabstand ist groesser als der Spaltenabstand, weil untereinander
   kein leerer Raum die Bloecke trennt - dort stossen Text und naechste
   Zeichnung sonst aneinander. */
.np-grid--steps { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-12) var(--space-10); }

.np-rule--gap { margin: var(--space-5) 0; }
.np-rule {
    height: 1px;
    border: 0;
    margin: 0;
    /* In Prozent statt in Pixeln: die Linie wird auch in einer 200 px
       schmalen Spalte noch sichtbar, nicht nur ueber die volle Breite. */
    background: linear-gradient(to right,
        transparent,
        var(--color-divider) 10%,
        var(--color-divider) 90%,
        transparent);
}
/* Abstands-Helfer. Bewusst wenige: vier Stufen reichen, alles andere
   gehoert in die Klasse des Bausteins. */
.np-mt-s  { margin-top: var(--space-3); }
.np-mt-m  { margin-top: var(--space-5); }
.np-mt-l  { margin-top: var(--space-8); }
.np-mt-xl { margin-top: var(--space-10); }
.np-selfstart { align-self: flex-start; }
.np-strong { color: var(--color-text); }

.np-glowline {
    height: 1px;
    background: linear-gradient(to right, transparent,
        color-mix(in srgb, var(--color-accent) 70%, transparent), transparent);
    opacity: .7;
}


/* ------------------------------------------------------------------
   Typografische Sonderformen
   ------------------------------------------------------------------ */

.np-display {
    text-wrap: balance;
    font-family: var(--font-heading);
    font-size: var(--text-display);
    line-height: 1.05;
    letter-spacing: -0.025em;
    margin: var(--space-4) 0 0;
    font-weight: var(--weight-heading);
}
.np-lead {
    font-size: var(--text-lg);
    line-height: 1.55;
    color: var(--color-neutral-300);
    margin: var(--space-4) 0 0;
    max-width: 50ch;
    text-wrap: pretty;
}
.np-kicker {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-accent);
    font-family: var(--font-body);
    margin: 0;
}
.np-kicker--center { justify-content: center; }

/* Zahlen und Preise tragen die Schrift der Wortmarke */
.np-num {
    font-family: var(--font-display);
    font-weight: 700;
    letter-spacing: 0;
}
/* Der Preis steht weiss. Er ist ohnehin die groesste Zahl auf der Karte -
   in Gelb dazu waere die Karte an drei Stellen laut und nirgends klar. */
.np-price { font-family: var(--font-display); font-weight: 700; font-size: var(--text-lg); }
.np-price__unit {
    font-family: var(--font-body);
    font-weight: 400;
    font-size: var(--text-xs);
    color: var(--color-neutral-500);
}
.np-price--old {
    font-family: var(--font-body);
    font-size: var(--text-sm);
    color: var(--color-neutral-500);
    text-decoration: line-through;
}

.np-meta,
.card-meta {
    font-size: var(--text-sm);
    color: var(--color-neutral-400);
    margin: 0;
}
/* Zwei kurze Angaben in einer Zeile. Getrennt wird allein ueber den
   Abstand - ein Trennzeichen dazwischen gibt es bewusst nicht. Jeder
   Teil ist ein eigenes <span>, sonst fasst Flex den Text zu einem
   einzigen Kasten zusammen und die Luecke faellt weg. Reicht der Platz
   nicht, rutscht der zweite Teil in die naechste Zeile. */
.np-parts {
    display: flex;
    flex-wrap: wrap;
    gap: 0 var(--space-3);
}
/* Der Erklaersatz unter einem Bedienelement. Er stand bisher mal ohne
   Abstand am Kasten, mal 8 px darunter, mal 10, 12 oder 14 - je nachdem,
   was davor stand und wer zuletzt eine Sonderregel geschrieben hatte.
   Eine Klasse, ein Abstand: 12 px, dasselbe Mass wie zwischen zwei
   Feldern. In einer .np-stack bringt deren gap die 12 px schon mit -
   dort waere die Angabe doppelt. */
.np-hint { margin-top: var(--space-3); }
/* Steht der Satz in einem Kasten, der seine Kinder ohnehin auf Abstand
   haelt, kommt der Abstand von dort. Ohne diese Zeile zaehlt beides und
   der Satz rutscht doppelt so weit weg - im Anfrage-Kasten waren das
   26 px statt 12. In einem .field bleibt die eigene Angabe stehen:
   dessen gap von 5 px trennt Beschriftung und Feld, nicht Feld und
   Erklaerung - und die Fehlerzeile darunter rechnet genauso. */
.np-stack > .np-hint,
.card > .np-hint { margin-top: 0; }
/* Im .field trennt dessen gap von 5 px die Beschriftung vom Feld. Was
   UNTER dem Feld steht, soll trotzdem dieselben 12 px Abstand haben wie
   ueberall sonst - also wird der gap abgezogen. Die Fehlerzeile rechnet
   mit, damit Hinweis und Fehler an derselben Stelle stehen. */
.field > .np-hint,
.field > .field__error { margin-top: calc(var(--space-3) - 5px); }

.np-muted { color: var(--color-neutral-400); }
.np-note { font-size: var(--text-sm); color: var(--color-neutral-400); }
/* Mittig, als Satz unter einem ganzen Raster (Videos der Artikelseite). */
.np-note--mitte { text-align: center; }
/* Ein Symbol vor dem Hinweis (meist "info"). Inline statt flex, damit
   der Satz normal umbricht und mittig bleibt; der Versatz setzt das
   Symbol auf die Mitte der Kleinbuchstaben. Cyan, weil es einordnet
   und nicht zur Tat ruft (siehe Farben in Design.md). */
.np-note > .icon {
    /* Grundregel ist svg { display: block } - hier soll es im Satz stehen. */
    display: inline-block;
    vertical-align: -.2em;
    margin-right: var(--space-1);
    color: var(--color-accent2-300);
}
/* Fliesstext in einem Baustein: Grundgroesse, eine Stufe leiser als die
   Ueberschrift darueber, aber nicht so leise wie .np-note. Newsletterband
   und Ablaufschritte teilen sich die Klasse - auf derselben Seite sollen
   zwei Absaetze gleichen Ranges nicht verschieden gross sein. */
.np-text { color: var(--color-neutral-300); max-width: 46ch; }


/* ==================================================================
   4. Bausteine
   ================================================================== */

/* ---------- Knopf ----------
   Knopf, Eingabefeld und Hinweis: css/bausteine.css (einmal fuer alle Bereiche). */

/* Abstand vor dem Absende-Knopf: css/bausteine.css (gilt auch im Kundenkonto). */

/* ---------- Symbole ----------
   Ein Sprite mit den paar Zeichen, die wirklich vorkommen (Phosphor,
   MIT). Kein Icon-Webfont: der waegt eine halbe Megabyte. */
.icon {
    width: 1.15em;
    height: 1.15em;
    flex: 0 0 auto;
    fill: currentColor;
}
.icon--lg { width: 22px; height: 22px; }
.icon--accent { color: var(--color-accent); }

/* ---------- Karte ---------- */
/* Jede Karte ist ein Stueck Knetmasse: runder Rand, Lichtkante oben
   links, Tiefe unten rechts. .elev-* legt nur noch den Wurf darunter
   dazu - deshalb steht die Grundform hier und nicht dort. */
.card {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-5);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
    color: var(--color-text);
    box-shadow: var(--clay-licht), var(--clay-tiefe);
}
.card--pad { padding: var(--space-6); gap: var(--space-3); }
/* Die Kategorie ueber dem Kartentitel traegt den zweiten Akzent. So
   teilen sich die beiden Farben die Arbeit: Cyan ordnet ein (Kategorie,
   Merkliste), Gelb ruft zur Tat (Knopf, Marke). Stuende beides in einer
   Farbe, schriee die ganze Karte auf einmal. */
.card-kicker {
    font-size: var(--text-sm);
    color: var(--color-accent2-300);
}
.card-title {
    font-family: var(--font-heading);
    /* Kartentitel sind klein - 700 statt 800, sonst laufen die Buchstaben zu. */
    font-weight: 700;
    font-size: var(--text-base);
    line-height: 1.3;
    margin: 0;
}
.card-title--lg { font-size: var(--text-xl); }
.card-body { margin: 0; font-size: var(--text-sm); color: var(--color-neutral-300); }

.elev-sm { box-shadow: var(--shadow-sm); }
.elev-md { box-shadow: var(--shadow-md); }
.elev-lg { box-shadow: var(--shadow-lg); }

/* ---------- Etikett ---------- */
.tag {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-2);
    border-radius: var(--radius-pill);
    font-size: var(--text-xs);
    line-height: 1.4;
    white-space: nowrap;
}
/* Die Marke, die etwas hervorhebt ("Beliebteste Wahl", "Top"): Umriss in
   der Hausfarbe. Gefuellt war sie auf jeder zweiten Karte ein gelber
   Fleck - die Flaeche gehoert dem Knopf, der etwas tut. */
.tag-accent {
    background: color-mix(in srgb, var(--color-accent) 10%, transparent);
    border: 1px solid color-mix(in srgb, var(--color-accent) 55%, transparent);
    color: var(--color-accent-300);
    font-weight: 600;
    letter-spacing: .01em;
}
/* Voll: das Etikett auf einem Foto (MediaBox, "Bestseller", "6er-Set").
   Die durchscheinende Fassung oben verschwindet auf hellen Fotos - viele
   Artikelfotos sind freigestellt auf Weiss. Voll im Akzent mit dunkler
   Schrift, dieselben Farben wie der Hauptknopf: steht auf Weiss wie auf
   dunklem Grund. */
.tag-voll {
    background: var(--color-accent);
    border: 1px solid var(--color-accent);
    color: var(--color-on-accent);
    font-weight: 600;
    letter-spacing: .01em;
}
.tag-neutral { background: var(--color-neutral-800); color: var(--color-neutral-200); }
/* Schlagworte am Artikel und am Paket: der zweite Akzent. Sie sind
   Beiwerk und sollen der Hausfarbe nicht die Schau stehlen. */
.tag-outline {
    border: 1px solid var(--color-accent2-700);
    background: var(--color-accent2-900);
    color: var(--color-accent2-200);
}
.tag-outline .icon { color: var(--color-accent2-300); }
.np-product .tag { font-size: var(--text-sm); padding: var(--space-1) var(--space-3); }
.tag .icon { width: 12px; height: 12px; }

/* ---------- Formular ---------- */
.field {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}

/* Sicherheitscode (FormCaptcha): Bild und "Neues Bild" nebeneinander,
   darunter das Eingabefeld. Das Bild behaelt seine Masse (180 x 60),
   rechts daneben der runde Knopf "Neues Bild" (Symbol). */
.np-captcha__zeile {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}
.np-captcha__zeile > .btn { flex: 0 0 auto; }
/* Alles Getippte erscheint gross - wie im Bild. Geprueft wird ohnehin
   ohne Ruecksicht auf Gross/Klein (CaptchaNormalize). */
.np-captcha__eingabe { text-transform: uppercase; }
.np-captcha__bild {
    display: block;
    flex: 0 1 auto;
    min-width: 0;
    max-width: 100%;
    height: auto;
    border: var(--linie);
    border-radius: var(--radius-md);
}

/* Eingeklappt: ohne diese Zeile gewinnt das display:flex darueber gegen
   die Browserregel fuer [hidden], und das Feld bliebe sichtbar. */
.field[hidden] { display: none; }
.field > label {
    font-size: var(--text-sm);
    color: var(--color-neutral-400);
}
/* Orange-Rot: ein rosastichiges Rot war neben der frueheren Hausfarbe
   nicht als Fehler zu erkennen, und neben Gelb traegt Orange-Rot gut. */

/* Fehlermeldung unter einem Feld: Form und Farbe aus bausteine.css
   (derselbe Kasten wie jeder Fehlerhinweis). Hier nur der Abstand zum
   Feld darueber, damit sie nicht daran klebt. */
.field__error { margin-top: var(--space-3); }
/* Leer ist kein Fehler: ohne diese Zeile stuende ueberall ein leerer
   Kasten, denn die Absaetze stehen schon im Quelltext bereit. */
.field__error:empty { display: none; }

/* Eingabefeld (.input): css/bausteine.css */

/* Kontrollkaestchen (Datenschutz-Bestaetigung): Aussehen aus
   css/bausteine.css, hier nur die Lage neben dem Text. */
.field input[type="checkbox"] { margin-top: var(--space-1); }
.field label.np-row { align-items: flex-start; font-size: var(--text-sm); color: var(--color-neutral-300); }

/* Ein Feld je Zeile (Betreiber, 15.10.2026). Vorher standen Name,
   E-Mail und Telefon nebeneinander, so viele wie passten - mit einer
   Fehlermeldung unter einem davon wurde die Reihe unruhig. Paare, die
   zusammengehoeren, stehen weiter nebeneinander: PLZ und Ort
   (.formgrid__row) und ausdrueckliche Paare (.formgrid--zwei). */
.formgrid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-3);
}

/* PLZ und Ort gehoeren zusammen. Sie stehen deshalb nicht im freien Fluss
   des Rasters - dort waeren sie je nach Breite auseinandergerissen -,
   sondern in einer eigenen Zeile ueber die volle Breite, die PLZ schmal
   davor. Auch auf dem Telefon bleibt es bei zweien: eine PLZ braucht
   keine ganze Zeile. */
.formgrid__row {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: minmax(96px, 148px) 1fr;
    gap: var(--space-3);
}

/* Dieselbe volle Breite fuer ein einzelnes Feld: die freiwillige Firma
   ueber den anderen. */
.formgrid__row--wide { grid-template-columns: 1fr; }

/* Genau zwei Spalten statt so vieler, wie hineinpassen - fuer Formulare
   aus Paaren (Vor- und Nachname, E-Mail und Telefon), in denen eine
   leere dritte Spalte wie ein vergessenes Feld aussaehe. */
.formgrid--zwei { grid-template-columns: repeat(2, minmax(0, 1fr)); }

/* Auf dem Telefon bekommt die PLZ nur, was fuenf Ziffern brauchen - der
   Ortsname ist laenger und soll den Rest haben. */
@media (max-width: 480px) {
    .formgrid__row:not(.formgrid__row--wide) { grid-template-columns: 104px 1fr; }
    .formgrid--zwei { grid-template-columns: minmax(0, 1fr); }
}

/* Meldet eines der beiden Felder einen Fehler, rutschen PLZ und Ort
   untereinander. Nebeneinander stuenden auch die Meldungen nebeneinander,
   und in der schmalen PLZ-Spalte wird aus einem Satz ein Wortturm. Beim
   Ausbessern ist Lesbarkeit wichtiger als die Briefform. */
.formgrid__row:not(.formgrid__row--wide):has(.field--error) {
    grid-template-columns: 1fr;
}

/* Honeypot: fuer Menschen unsichtbar, fuer Bots verlockend */
.honeypot {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* Meldung nach dem Absenden (.notice): css/bausteine.css */

/* ---------- Segment (zwei Alternativen, eine gewaehlt) ---------- */
.seg {
    flex-wrap: wrap;
    /* In einer Flex-Spalte wuerde das Segment sonst auf volle Breite
       gezogen - es soll aber nur so breit sein wie seine beiden Optionen. */
    align-self: flex-start;
    display: inline-flex;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    overflow: hidden;
    /* Wie die Eingabefelder eine Mulde: die Wahl liegt darin, sie steht
       nicht darauf. */
    background: color-mix(in srgb, var(--color-bg) 80%, var(--color-surface));
    box-shadow: inset 1px 2px 4px var(--color-mulde-dunkel), inset -1px -1px 2px var(--color-mulde-hell);
    padding: var(--space-1);
    gap: var(--space-05);
}
.seg-opt {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3);
    background: none;
    border: 0;
    color: var(--color-neutral-400);
    font: inherit;
    font-size: var(--text-sm);
    cursor: pointer;
}
/* Kein Trennstrich mehr: die gewaehlte Option hebt sich durch ihre
   eigene Flaeche ab, ein Strich daneben waere doppelt. */
/* Beim Ueberfahren keine Flaeche, nur hellere Schrift: ein grauer
   Kasten in der Mulde sah aus wie eine zweite Auswahl. */
.seg-opt:hover { color: var(--color-neutral-200); }
.seg-opt.on,
.seg-opt[aria-pressed="true"] {
    color: var(--color-accent);
    box-shadow: inset 0 0 0 1px var(--color-accent);
}
/* Als Radio-Label gebaut, damit es ohne JavaScript funktioniert */
.seg input { position: absolute; opacity: 0; pointer-events: none; }
.seg label.seg-opt:has(input:checked) {
    color: var(--color-on-accent);
    background: var(--color-accent);
    border-radius: calc(var(--radius-md) - 4px);
    box-shadow:
        inset 1px 1px 2px var(--color-wahl-hell),
        inset -1px -2px 5px var(--color-wahl-dunkel),
        0 3px 7px -6px color-mix(in srgb, var(--color-accent) 40%, transparent);
}
.seg label.seg-opt:has(input:checked) .icon { color: var(--color-on-accent); }
.seg label.seg-opt:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: -2px; }
/* Nicht waehlbar (Selbstabholung bei Pflichtaufbau im Korb): sichtbar,
   aber ausgegraut - so bleibt erkennbar, dass es die Option gibt und
   warum sie gerade nicht geht (der Hinweis steht darunter). */
.seg-opt.is-gesperrt { color: var(--color-neutral-600); cursor: not-allowed; }
.seg-opt.is-gesperrt:hover { color: var(--color-neutral-600); }

/* Aufbau durch Fachpersonal in der Anfrage: feste Zeile statt Haken */
/* Summe: die gerechnete Strecke hinter "Lieferung", und der Hinweis,
   solange die PLZ fehlt. */
.np-sum__zusatz { color: var(--color-neutral-500); font-size: var(--text-sm); margin-left: var(--space-1); }
/* Steht auch im Preisfeld (.np-price, Display-Schrift fett) - darum
   Schrift und Staerke ausdruecklich zurueck auf normalen Text. */
.np-sum__offen {
    font-family: var(--font-body);
    font-weight: 400;
    font-size: var(--text-sm);
    color: var(--color-neutral-500);
}
/* Hinweg und Rueckweg in der Anfrage: kleine Ueberschrift ueber jedem
   Segment, damit die beiden Zeilen nicht als eine gelesen werden. */
.np-shipping__label {
    margin: 0 0 var(--space-2);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-neutral-400);
}
.np-shipping__label--zweite { margin-top: var(--space-4); }
.np-pflichtaufbau { margin: 0; font-size: var(--text-base); color: var(--color-neutral-300); }
.np-pflichtaufbau .icon { color: var(--color-accent); flex: 0 0 auto; }
.np-pflichtaufbau strong { color: var(--color-text); font-weight: 500; }

/* ---------- Bildflaeche ----------
   Solange keine Produktfotos da sind, steht hier ein ruhiger Platzhalter
   mit dem Symbol der Kategorie - besser als ein gebrochenes Bild. */
.np-media {
    position: relative;
    overflow: hidden;
    border-radius: var(--radius-sm);
    background: var(--color-neutral-900);
    aspect-ratio: 4 / 3;
}
/* Der .lighten-Wrapper spannt sich ueber die ganze Flaeche. Ohne das
   absolute Positionieren haette er keine Hoehe, und das height:100% des
   Bildes liefe ins Leere - das Foto wuerde in Originalproportion stehen
   statt die Flaeche zu fuellen. */
.np-media > .lighten {
    position: absolute;
    inset: 0;
}
.np-media picture {
    display: block;
    width: 100%;
    height: 100%;
}
.np-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/* Kleines quadratisches Vorschaubild fuer Listenzeilen: die Merkliste
   im Kopf und die Anfrageseite. Quadratisch und nicht 4:3, weil es
   neben einer zweizeiligen Zeile steht - ein Rechteck waere entweder zu
   hoch oder zu schmal.

   Der Platzhalter bekommt hier kein Wort: Der Artikelname steht
   unmittelbar daneben, und bei 52 px waere er ohnehin unlesbar. Deshalb
   ruft die Zeile MediaBox auch mit alt="" auf - das Bild ist Schmuck
   neben dem Namen, kein zweiter Traeger derselben Aussage. */
.np-media--mini {
    width: 52px;
    height: 52px;
    flex: 0 0 auto;
    aspect-ratio: auto;
}
.np-media--mini .np-media__empty { padding: 0; gap: 0; }
.np-media--mini .np-media__empty .icon { width: 22px; height: 22px; }

@media (max-width: 480px) {
    .np-media--mini { width: 44px; height: 44px; }
}

.np-media--lg { border-radius: var(--radius-lg); }
.np-media--wide { aspect-ratio: 16 / 9; }
.np-media--band { aspect-ratio: 3 / 1; }
.np-media--tall { aspect-ratio: 3 / 4; }
.np-media--portrait { aspect-ratio: 4 / 5; }
/* Grafik mit Beschriftung im Bild (Groessenvergleich der Startseite).
   Ohne Kachel: der Grund der Grafik ist der Seitengrund. contain statt
   cover, damit keine Beschriftung am Rand abgeschnitten wird. Unter
   640 px liefert MediaBox den schmalen Ausschnitt (foto_schmal) - die
   Grenze muss mit "schmal_bis" im Aufruf uebereinstimmen.

   Die Raender laufen weich aus. Noetig, weil .lighten hier nicht mit
   dem Seitengrund verrechnet wird: <main> bildet mit z-index eine eigene
   Ebene, der Farbschein (.np-aurora) liegt ausserhalb. Ohne Verlauf stand
   die Grafik als dunkles Rechteck im Schein. Die Breiten folgen dem
   Abstand der Beschriftung zum Bildrand (rechts und unten 3 Prozent,
   in der Handyfassung reicht sie seitlich bis an den Rand). */
.np-media--vergleich {
    aspect-ratio: 12 / 5;
    background: transparent;
    --np-vergleich-maske:
        linear-gradient(to right, transparent, var(--maske-voll) 6%, var(--maske-voll) 97.5%, transparent),
        linear-gradient(to bottom, transparent, var(--maske-voll) 5%, var(--maske-voll) 97.5%, transparent);
    -webkit-mask-image: var(--np-vergleich-maske);
    -webkit-mask-composite: source-in;
    mask-image: var(--np-vergleich-maske);
    mask-composite: intersect;
}
.np-media--vergleich img { object-fit: contain; }
@media (max-width: 640px) {
    .np-media--vergleich {
        aspect-ratio: 24 / 17;
        --np-vergleich-maske: linear-gradient(to bottom, transparent, var(--maske-voll) 5%, var(--maske-voll) 97%, transparent);
    }
}

/* ==================================================================
   Abholen oder liefern (Startseite): ein Umschalter (.seg), zwei
   Ansichten. Sichtbar ist die zum gewaehlten Radioknopf - reines CSS,
   ohne JavaScript bedienbar. Ein Browser ohne :has() zeigt beide
   untereinander, verloren geht dabei nichts.
   ================================================================== */
.np-wahl__ansicht { margin-top: var(--space-8); }
.np-wahl__ansicht > h3 { margin: 0; }
.np-wahl:has(input[value="lieferung"]:checked) .np-wahl__ansicht--abholung,
.np-wahl:has(input[value="abholung"]:checked) .np-wahl__ansicht--lieferung { display: none; }

/* ==================================================================
   Kontaktlose Abholung und Rueckgabe (partials/contactless-handover.php)

   Eine Karte, drei Teile: Symbol, Text, Rueckgabezeiten. Breit stehen
   sie nebeneinander, darunter Symbol und Text oben, Zeiten unten, auf
   dem Telefon alles untereinander.

   Das Symbol sitzt auf einem eigenen kleinen Kissen mit dem Verlauf
   Gelb nach Cyan - derselbe Verlauf wie in den Zeichnungen von
   "So laeuft's", nur leise. Das Zeichen selbst ist Gelb: es ist das
   Erkennungszeichen des Abschnitts.

   Der Samstag ist die Ausnahme und deshalb die einzige Zeile mit
   Akzentrand und Marke. Die flexiblen Tage bleiben ruhig.
   ================================================================== */
.np-handover {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) minmax(0, 380px);
    align-items: start;
    gap: var(--space-6) var(--space-8);
}
.np-handover__badge {
    display: grid;
    place-items: center;
    width: var(--space-24);
    height: var(--space-24);
    border-radius: var(--radius-lg);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--color-accent) 16%, transparent),
        color-mix(in srgb, var(--color-accent2) 16%, transparent));
    box-shadow: var(--clay-licht), var(--clay-tiefe);
    color: var(--color-accent);
}
.np-handover__badge .icon { width: var(--space-12); height: var(--space-12); }
.np-handover__text {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}
.np-handover__text .np-text { margin: var(--space-1) 0 0; }
.np-handover__label {
    margin: 0 0 var(--space-3);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--color-neutral-400);
}
.np-handover__list {
    display: grid;
    gap: var(--space-2);
    margin: 0;
}
.np-handover__row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-1) var(--space-4);
    padding: var(--space-3) var(--space-4);
    border: var(--linie);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--color-text) 3%, transparent);
}
.np-handover__row dt {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    font-weight: 600;
}
.np-handover__row dd {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--color-neutral-300);
}
.np-handover__row--fixed {
    border-color: color-mix(in srgb, var(--color-accent) 45%, transparent);
    background: color-mix(in srgb, var(--color-accent) 6%, transparent);
}
.np-handover__row--fixed dd {
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--color-accent-300);
    white-space: nowrap;
}

@media (max-width: 960px) {
    .np-handover { grid-template-columns: auto minmax(0, 1fr); }
    .np-handover__times { grid-column: 1 / -1; }
}
@media (max-width: 520px) {
    .np-handover { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
    .np-handover__badge { width: var(--space-16); height: var(--space-16); }
    .np-handover__badge .icon { width: var(--space-8); height: var(--space-8); }
}

/* ==================================================================
   Lieferwagen-Animation (Startseite, Abschnitt "Lieferservice",
   partials/delivery-van.php)

   Ablauf: Wagen faehrt herein und bremst, Hecktuer geht auf, die vier
   Boxen werden nacheinander ausgeladen und neben den Wagen gestellt.
   Rund 6,5 s, einmal.

   Endbild ist der Grundzustand: ohne JavaScript und bei
   prefers-reduced-motion steht der Wagen mit offener Tuer da, die Boxen
   daneben. Das kleine Skript direkt unter der Zeichnung (delivery-van.php)
   setzt sofort .np-van--bereit (Startzustand, noch vor dem ersten Bild -
   sonst blitzt nach dem Neuladen das Endbild auf) und, sobald sie zu gut
   einem Drittel sichtbar ist, .np-van--los.

   Die Boxen sind waehrend der Wartezeit vor dem Ausladen unsichtbar
   (0 % der Keyframes): sie stehen dann schon im Laderaum, der Wagen ist
   aber noch auf der Fahrt herein.

   Die Zahlen in translate() sind Koordinaten der Zeichnung (viewBox),
   keine Abstaende der Seite. Schriftgroesse und -farbe der Aufschrift
   stehen als Attribute im SVG - sie gehoeren zur Zeichnung. Das Logo
   auf dem Schild ist die echte Logodatei (<image>), kein Text.
   ================================================================== */
.np-van {
    position: relative;
    overflow: hidden;   /* der einfahrende Wagen darf kein seitliches Scrollen ausloesen */
}
.np-van__svg {
    display: block;
    width: 100%;
    height: auto;
}
.np-van__zeile { font-family: var(--font-body); }

.np-van__wind,
.np-van__kegel { opacity: 0; }

.np-van__rad,
.np-van__karosse,
.np-van__tuer {
    transform-box: fill-box;
    transform-origin: center;
}
.np-van__karosse { transform-origin: 20% 100%; }
.np-van__tuer { transform-origin: 0% 50%; }   /* Scharnier links */

/* ---------- Startzustand (setzt das Skript in delivery-van.php) ---------- */
.np-van--bereit .np-van__fahrt { transform: translateX(120%); }
.np-van--bereit .np-van__tuer { transform: scaleX(0); }
.np-van--bereit .np-van__box--pa110a { transform: translate(-836px, -357px); opacity: 0; }
.np-van--bereit .np-van__box--ta18 { transform: translate(-676px, -155px); opacity: 0; }
.np-van--bereit .np-van__box--pa502a { transform: translate(-652px, -155px); opacity: 0; }
.np-van--bereit .np-van__box--soundboks { transform: translate(-609px, -155px); opacity: 0; }

/* ---------- Ablauf ---------- */
.np-van--los .np-van__fahrt { animation: np-van-fahrt 1.7s cubic-bezier(.16, .74, .24, 1) both; }
.np-van--los .np-van__rad { animation: np-van-rad 1.7s cubic-bezier(.16, .74, .24, 1) both; }
.np-van--los .np-van__karosse { animation: np-van-bremsen .5s ease-out 1.45s both; }
.np-van--los .np-van__wind { animation: np-van-wind 1.5s ease-out both; }
.np-van--los .np-van__kegel { animation: np-van-wind 1.9s ease-out both; }
.np-van--los .np-van__tuer { animation: np-van-tuer .6s cubic-bezier(.3, .8, .3, 1.1) 2.05s both; }
.np-van--los .np-van__box--pa110a { animation: np-van-raus-pa110a .95s ease-in-out 2.75s both; }
.np-van--los .np-van__box--ta18 { animation: np-van-raus-ta18 .95s ease-in-out 3.5s both; }
.np-van--los .np-van__box--pa502a { animation: np-van-raus-pa502a .95s ease-in-out 4.25s both; }
.np-van--los .np-van__box--soundboks { animation: np-van-raus-soundboks .95s ease-in-out 5s both; }

@keyframes np-van-fahrt {
    from { transform: translateX(120%); }
    to   { transform: translateX(0); }
}
@keyframes np-van-rad {
    from { transform: rotate(0deg); }
    to   { transform: rotate(-1080deg); }
}
@keyframes np-van-bremsen {
    0%   { transform: rotate(0deg); }
    35%  { transform: rotate(-1.4deg) translateY(3px); }
    70%  { transform: rotate(.5deg); }
    100% { transform: rotate(0deg); }
}
@keyframes np-van-wind {
    0%   { opacity: 1; }
    100% { opacity: 0; }
}
@keyframes np-van-tuer {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
}
@keyframes np-van-raus-pa110a {
    0%   { transform: translate(-836px, -357px); opacity: 0; }
    6%   { opacity: 1; }
    50%  { transform: translate(-683px, -371px); }
    82%  { transform: translate(-78px, -18px); }
    100% { transform: translate(0, 0); opacity: 1; }
}
@keyframes np-van-raus-ta18 {
    0%   { transform: translate(-676px, -155px); opacity: 0; }
    6%   { opacity: 1; }
    50%  { transform: translate(-494px, -169px); }
    82%  { transform: translate(-56px, -18px); }
    100% { transform: translate(0, 0); opacity: 1; }
}
@keyframes np-van-raus-pa502a {
    0%   { transform: translate(-652px, -155px); opacity: 0; }
    6%   { opacity: 1; }
    50%  { transform: translate(-332px, -169px); }
    82%  { transform: translate(-37px, -18px); }
    100% { transform: translate(0, 0); opacity: 1; }
}
@keyframes np-van-raus-soundboks {
    0%   { transform: translate(-609px, -155px); opacity: 0; }
    6%   { opacity: 1; }
    50%  { transform: translate(-186px, -169px); }
    82%  { transform: translate(-22px, -18px); }
    100% { transform: translate(0, 0); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .np-van--bereit .np-van__fahrt,
    .np-van--bereit .np-van__tuer,
    .np-van--bereit .np-van__box { transform: none; opacity: 1; }
    .np-van--los * { animation: none !important; }
}

.np-media__empty {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    padding: var(--space-3);
    text-align: center;
    color: var(--color-neutral-700);
    background: radial-gradient(120% 100% at 50% 0%,
        color-mix(in srgb, var(--color-accent) 7%, transparent), transparent 70%);
}
.np-media__empty .icon { width: 26px; height: 26px; }
.np-media__empty span { font-size: var(--text-xs); color: var(--color-neutral-400); }

.np-media__tag {
    position: absolute;
    top: var(--space-2);
    left: var(--space-2);
}
/* Diagonales Band oben rechts: das laufende Angebot (MediaBox "band").
   Die andere Ecke als das Etikett, damit beide nebeneinander bestehen.
   Farben wie .tag-voll - lesbar auf weissen wie dunklen Fotos. Das Band
   ist breiter als die Ecke und wird von .np-media (overflow: hidden)
   abgeschnitten: so laeuft es sauber ueber beide Kanten. Flach, ohne
   Schatten, wie alle Flaechen. */
.np-media__band {
    position: absolute;
    top: var(--space-5);
    right: calc(var(--space-12) * -1);
    width: calc(var(--space-24) + var(--space-16));
    padding: var(--space-1) 0;
    transform: rotate(45deg);
    background: var(--color-accent);
    color: var(--color-on-accent);
    font-size: var(--text-xs);
    font-weight: 700;
    text-align: center;
    pointer-events: none;
}


/* ---------- Hinweisbox ----------
   Der blaue Kasten auf der Artikelseite und der Paketkarte, gepflegt im
   Adminbereich (partials/info-box.php). Er sagt, was VOR der Buchung zu
   klaeren ist - "haengt am Veranstaltungsort eine Rauchmelderanlage?".

   Kein Clay: die Box soll nicht wie die naechste Karte aussehen, sondern
   wie eine Randnotiz mit Nachdruck. Deshalb flache Flaeche, ein Rahmen
   und die kraeftige Kante links - dasselbe Muster, das jeder von
   Hinweiskaesten kennt.

   Symbol und Text stehen nebeneinander (grid statt flex), damit ein
   umgebrochener Text nicht unter das Symbol rutscht. */
.np-info {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-3);
    align-items: start;
    /* Oben und unten knapper als an den Seiten: der Kasten traegt meist
       nur zwei, drei Zeilen, und gleiches Polster ringsum liesse ihn
       dabei aufgeblasen wirken. */
    padding: var(--space-3) var(--space-4);
    border: 1px solid color-mix(in srgb, var(--color-info) 34%, transparent);
    /* Die linke Kante traegt die Farbe voll, der Rest nur angedeutet -
       so liest sich der Kasten von der Seite als Hinweis, ohne dass
       ringsum ein blauer Rahmen steht. */
    border-left: 3px solid var(--color-info);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--color-info) 13%, var(--color-surface));
    color: var(--color-neutral-200);
    font-size: var(--text-sm);
    line-height: 1.5;
}
.np-info__icon {
    width: 20px;
    height: 20px;
    color: var(--color-info);
    /* Auf die erste Textzeile ausgerichtet, nicht auf die Kastenmitte -
       bei drei Zeilen Text saehe die Mitte aus wie ein Versehen. */
    margin-top: 1px;
}
.np-info__text > p { margin: 0; }
/* Knapp, nicht luftig: Ueberschrift und Text sind ein Gedanke, kein
   Absatzwechsel. Der Abstand trennt sie gerade so weit, dass die
   Ueberschrift als solche zu lesen ist. */
.np-info__text > p + p { margin-top: var(--space-1); }
.np-info__titel {
    font-weight: 600;
    color: var(--color-info-300);
}


/* ==================================================================
   5. Effekte

   Drei driftende Farbwolken hinter dem Inhalt, darueber eine feine
   Filmkoernung. Beides laesst sich per .no-fx am body abschalten und
   respektiert prefers-reduced-motion.
   ================================================================== */

/* Inhalt und Fuss liegen ueber den Farbwolken. Die Kopfleiste steht
   hier bewusst NICHT mit drin: sie bringt Position (sticky) und Ebene
   (z-index 40) selbst mit (css/bausteine.css). Stuende sie hier, gewaenne
   diese Regel - style.css wird nach bausteine.css geladen -, und die
   Kopfleiste samt Merkliste laege unter dem Seiteninhalt. */
main,
footer { position: relative; z-index: 1; }

.np-aurora {
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;
}
.np-aurora i {
    position: absolute;
    display: block;
    border-radius: 50%;
    filter: blur(90px);
    opacity: .5;
    mix-blend-mode: screen;
}
.np-aurora i:nth-child(1) {
    width: 46vw; height: 46vw; left: -10vw; top: -14vw;
    background: color-mix(in srgb, var(--color-accent) 42%, transparent);
    animation: npDrift 34s ease-in-out infinite alternate;
}
.np-aurora i:nth-child(2) {
    width: 34vw; height: 34vw; right: -8vw; top: 22vh;
    /* Der kuehle Gegenpol zur gelben Wolke links - zusammen ergeben sie
       das Buehnenlicht, das die Seite von einer einfarbigen unterscheidet. */
    background: color-mix(in srgb, var(--color-accent2) 24%, transparent);
    animation: npDrift 46s ease-in-out infinite alternate-reverse;
}
.np-aurora i:nth-child(3) {
    width: 40vw; height: 40vw; left: 24vw; bottom: -18vw;
    background: color-mix(in srgb, var(--color-section-ghost) 40%, transparent);
    animation: npDrift 58s ease-in-out infinite alternate;
}
@keyframes npDrift {
    from { transform: translate3d(0, 0, 0) scale(1); }
    to   { transform: translate3d(6vw, -4vh, 0) scale(1.18); }
}

body::after {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 9;
    pointer-events: none;
    opacity: .035;
    background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxNDAnIGhlaWdodD0nMTQwJz48ZmlsdGVyIGlkPSduJz48ZmVUdXJidWxlbmNlIHR5cGU9J2ZyYWN0YWxOb2lzZScgYmFzZUZyZXF1ZW5jeT0nLjg1JyBudW1PY3RhdmVzPSczJy8+PC9maWx0ZXI+PHJlY3Qgd2lkdGg9JzE0MCcgaGVpZ2h0PScxNDAnIGZpbHRlcj0ndXJsKCNuKScvPjwvc3ZnPg==");
}

/* Scroll-Reveal. Die Klasse setzt erst JavaScript - ohne JavaScript ist
   alles von Anfang an sichtbar. */
.np-reveal { opacity: 0; transform: translateY(14px); }
.np-reveal.in {
    opacity: 1;
    transform: none;
    transition: opacity .7s cubic-bezier(.2, .7, .2, 1), transform .7s cubic-bezier(.2, .7, .2, 1);
}

.no-fx .np-aurora,
.no-fx::after { display: none; }
.no-fx .np-reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    .np-aurora i { animation: none; }
    .np-reveal { opacity: 1; transform: none; }
}


/* ==================================================================
   6. Rahmen
   ================================================================== */

/* ---------- Kopf ----------
   Kopfleiste, Logo und Menuepunkt (.np-nav, .np-logo, .np-navlink):
   css/bausteine.css - die Kundenanmeldung benutzt dieselben. */

.np-navmain ul {
    display: flex;
    align-items: center;
    gap: var(--space-05);
    margin: 0;
    padding: 0;
    list-style: none;
}

.np-nav__actions { display: flex; align-items: center; gap: var(--space-2); }
.np-badge {
    margin-left: var(--space-1);
    min-width: 17px;
    height: 17px;
    padding: 0 var(--space-1);
    border-radius: var(--radius-sm);
    background: var(--color-accent);
    color: var(--color-bg);
    font-size: var(--text-xs);
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.np-burger { display: none; }

/* Das Aufklappmenue ist ein <details>. Das Blatt haengt unter dem Kopf -
   .np-nav ist sticky und damit positioniert, also bezieht sich das
   absolute Blatt darauf. */
.np-menu { position: static; }
.np-menu summary { list-style: none; }
.np-menu summary::-webkit-details-marker { display: none; }
.np-menu[open] .np-sheet { display: block; animation: np-sheet-auf 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) both; }

/* Das Burger-Symbol: drei Striche, die sich bei offenem Menue zum X
   drehen - der obere und untere kippen um 45 Grad in die Mitte, der
   mittlere zieht sich zusammen und verschwindet. Gleiche Groesse wie die
   Symbole der Nachbarknoepfe (1.15em). */
.np-burger__icon {
    position: relative;
    display: block;
    width: 1.15em;
    height: 1.15em;
}
.np-burger__icon i {
    position: absolute;
    left: 0.1em;
    right: 0.1em;
    height: 2px;
    border-radius: var(--radius-xs);
    background: currentColor;
    transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.2s ease;
}
.np-burger__icon i:nth-child(1) { top: calc(50% - 1px - 0.32em); }
.np-burger__icon i:nth-child(2) { top: calc(50% - 1px); }
.np-burger__icon i:nth-child(3) { top: calc(50% - 1px + 0.32em); }
.np-menu[open] .np-burger__icon i:nth-child(1) { transform: translateY(0.32em) rotate(45deg); }
.np-menu[open] .np-burger__icon i:nth-child(2) { transform: scaleX(0); opacity: 0; }
.np-menu[open] .np-burger__icon i:nth-child(3) { transform: translateY(-0.32em) rotate(-45deg); }

/* Aufklappmenue: ein <details>, das Blatt faehrt beim Oeffnen von oben
   herunter und laesst die Seite dahinter leicht durchscheinen - unscharf,
   wie die Kopfleiste selbst. */
.np-sheet {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    border-top: 1px solid var(--color-divider);
    /* 60 % Grund reicht auf der dunklen Seite gerade, damit Foto und
       Schrift dahinter als weiche Flecken durchkommen; der Text im Menue
       bleibt durch die Unschaerfe lesbar. */
    background: color-mix(in srgb, var(--color-bg) 60%, transparent);
    -webkit-backdrop-filter: blur(22px) saturate(150%);
    backdrop-filter: blur(22px) saturate(150%);
    box-shadow: var(--shadow-md);
    transform-origin: top center;
}
/* Ein Element mit backdrop-filter ist fuer seine Kinder die Grenze des
   Hintergrunds: solange die Kopfleiste selbst filtert, sieht das Blatt
   nur sie und nicht die Seite darunter. Bei offenem Menue filtert deshalb
   nur das Blatt, die Leiste wird kurz deckend. */
.np-nav:has(.np-menu[open]) {
    background: var(--color-bg);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
}
@keyframes np-sheet-auf {
    from { opacity: 0; transform: translateY(-12px) scaleY(0.96); }
    to   { opacity: 1; transform: none; }
}
/* Die Eintraege kommen kurz nacheinander nach - ein leiser Effekt, keine Show. */
.np-menu[open] .np-sheet li { animation: np-sheet-eintrag 0.32s ease-out both; }
.np-menu[open] .np-sheet li:nth-child(2) { animation-delay: 0.03s; }
.np-menu[open] .np-sheet li:nth-child(3) { animation-delay: 0.06s; }
.np-menu[open] .np-sheet li:nth-child(4) { animation-delay: 0.09s; }
.np-menu[open] .np-sheet li:nth-child(5) { animation-delay: 0.12s; }
.np-menu[open] .np-sheet li:nth-child(6) { animation-delay: 0.15s; }
.np-menu[open] .np-sheet li:nth-child(n+7) { animation-delay: 0.18s; }
@keyframes np-sheet-eintrag {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
    .np-menu[open] .np-sheet,
    .np-menu[open] .np-sheet li { animation: none; }
    .np-burger__icon i { transition: none; }
}
.np-sheet ul {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin: 0;
    padding: var(--space-3) 0 var(--space-4);
    list-style: none;
}
.np-sheet .np-navlink { font-size: var(--text-lg); padding: var(--space-2) var(--space-3); display: block; }

/* ---------- Fuss ---------- */
.np-foot { margin-top: var(--space-16); }
.np-footgrid {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr));
    gap: var(--space-8);
    /* padding-block, nie das Kurzformat: der Seitenabstand kommt von
       .np-wrap auf demselben Element - so steht der Fuss buendig mit
       dem Inhalt. */
    padding-block: var(--space-10) var(--space-8);
}
.np-footgrid h2 { font-size: var(--text-sm); font-weight: 600; }
.np-footgrid ul {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
.np-footlink {
    display: block;
    padding: var(--space-1) 0;
    color: var(--color-neutral-400);
    font-size: var(--text-base);
}
.np-footlink:hover { color: var(--color-accent-200); text-decoration: none; }
.np-foot__brand img { width: 160px; height: auto; }
.np-foot__claim {
    color: var(--color-neutral-400);
    font-size: var(--text-base);
    margin-top: var(--space-3);
    max-width: 260px;
}
.np-foot__bottom .np-footlink { display: inline-block; margin-right: var(--space-4); }
.np-foot__bottom {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    justify-content: space-between;
    padding-block: var(--space-4) var(--space-10);
    color: var(--color-neutral-600);
    font-size: var(--text-sm);
}


/* ---------- Sprachumschalter und Standortwahl ----------
   Ein <details>-Aufklappmenue, gebaut wie das Burger-Menue: der Knopf zeigt
   die aktuelle Sprache, die Liste alle verfuegbaren. Oeffnet und schliesst
   ohne JavaScript; main.js ergaenzt nur Klick-nach-draussen und Escape.

   Die Standortwahl (partials/locationswitcher.php) benutzt DIESELBEN Klassen
   plus .np-location - es ist dasselbe Bauteil mit anderem Inhalt. Eine
   zweite Klassenfamilie wuerde nur auseinanderlaufen.

   Die Flagge ist das einzige farbige Element im Kopf. Damit sie sich nicht
   vordraengt, sitzt sie klein und mit gedaempfter Deckkraft neben dem Text -
   erst beim Ueberfahren wird sie voll sichtbar. Die Akzentfarbe bleibt so,
   wie Design.md es will, der Marke und den Linien vorbehalten. */
/* Aufklappknopf (.np-sprache, auch fuer den Standort): Aussehen aus
   css/bausteine.css. Hier nur die Platzierung im Kopf und im Menue. */

/* Im Aufklappmenue auf schmalen Bildschirmen steht der Umschalter allein in
   einer Zeile und darf die volle Breite nehmen. Die Liste klappt dort nach
   unten auf, statt zu schweben - im schon offenen Menue waere ein
   schwebendes Untermenue nur im Weg. */
.np-sheet__sprache .np-sprache { display: block; }
.np-sheet__sprache .np-sprache__knopf { justify-content: center; width: 100%; padding-block: var(--space-2); }

.np-sheet__sprache .np-sprache__liste {
    position: static;
    margin-top: var(--space-1);
    box-shadow: none;
}

.np-sheet__sprache .np-sprache__eintrag { justify-content: center; padding-block: var(--space-2); }

/* Die Standortwahl: statt der Flagge ein Ortsmarker in gedaempfter
   Akzentfarbe - derselbe Kniff wie bei der Flagge, die Farbe draengt
   sich erst beim Ueberfahren vor. */
.np-location__icon {
    width: 15px;
    height: 15px;
    flex: 0 0 auto;
    color: var(--color-accent);
    opacity: .75;
}
.np-sprache__knopf:hover .np-location__icon,
.np-location[open] .np-location__icon { opacity: 1; }

/* Die Liste der Standorte ist links am Knopf ausgerichtet - der Knopf
   steht innen in der Kopfleiste, ein rechtsbuendiges Blatt liefe unter
   den Anfrage-Knopf. */
.np-location .np-sprache__liste { right: auto; left: 0; }
.np-sheet__location .np-sprache__liste { left: auto; }

/* Eventanschrift in der Anfrage: ein eigener Block unter der Versandart.
   Sie gehoert zur Fahrt, nicht zu den Kontaktdaten - und ohne Fahrt ist
   sie ganz weg (hidden am Block, nicht am einzelnen Feld). */
.np-eventort { margin-top: var(--space-5); }
.np-eventort__titel { margin-bottom: var(--space-2); }

/* Abholadresse in der Anfrage */
.np-pickup { display: flex; gap: var(--space-2); align-items: flex-start; }
.np-pickup .icon { color: var(--color-accent); flex: 0 0 auto; margin-top: var(--space-05); }
.np-pickup strong { color: var(--color-text); font-weight: 500; }
/* Derselbe Satzbau fuer den Stammkunden-Hinweis ueber den Kontaktfeldern. */
.np-konto-hinweis { margin: 0 0 var(--space-4); }
.np-konto-hinweis a { white-space: nowrap; }

/* ==================================================================
   7. Seiten
   ================================================================== */

/* ---------- Startseite: Hero ----------
   Ein Foto ueber die ganze Breite, der Text steht darin, unten links.
   Das Foto fuellt den Kasten (object-fit: cover), darueber ein dunkler
   Verlauf von unten und von links, damit Slogan und Knoepfe auf jedem
   Bildausschnitt lesbar bleiben. Die Hoehe haengt am Fenster, hat aber
   Grenzen: nie so flach, dass der Text nicht hineinpasst, nie so hoch,
   dass unter dem Kopf nur noch Bild steht. */
.np-hero {
    position: relative;
    isolation: isolate;
    min-height: clamp(460px, 68svh, 680px);
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
}
.np-hero__foto {
    position: absolute;
    inset: 0;
    z-index: -2;
    aspect-ratio: auto;
    border-radius: 0;
}
.np-hero__foto img { object-position: 50% 40%; }

/* Zwei Fotos, die ineinander ueberblenden. Das zweite liegt auf dem
   ersten und wird nur ein- und ausgeblendet - kein Wechsel der Quelle,
   also auch kein Flackern und kein Nachladen mitten in der Bewegung.

   Die Zeiten: gut sieben Sekunden steht ein Bild, gut eine Sekunde
   dauert der Uebergang. Langsam genug, dass es niemanden vom Lesen
   abhaelt, schnell genug, dass man es beim ersten Besuch bemerkt. */
.np-hero__foto--zwei {
    opacity: 0;
    animation: np-hero-wechsel 17s ease-in-out infinite;
}
.np-hero__foto--zwei img { object-position: 50% 35%; }

@keyframes np-hero-wechsel {
     0%, 42% { opacity: 0; }
    50%, 92% { opacity: 1; }
   100%      { opacity: 0; }
}

/* Wer Bewegung abbestellt hat, sieht das zweite Foto gar nicht: ein
   Dauerwechsel im Augenwinkel ist genau das, was die Einstellung
   verhindern soll. */
@media (prefers-reduced-motion: reduce) {
    .np-hero__foto--zwei { animation: none; opacity: 0; }
}
.np-hero__schleier {
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        linear-gradient(to top,
            var(--color-bg) 0%,
            color-mix(in srgb, var(--color-bg) 78%, transparent) 38%,
            color-mix(in srgb, var(--color-bg) 25%, transparent) 70%,
            color-mix(in srgb, var(--color-bg) 10%, transparent) 100%),
        linear-gradient(to right,
            color-mix(in srgb, var(--color-bg) 55%, transparent) 0%,
            transparent 65%);
}
.np-hero__inhalt {
    position: relative;   /* Bezug fuer die Karte rechts */
    width: 100%;
    padding-top: var(--space-24);
    padding-bottom: var(--space-12);
}
/* Die kleine Deutschlandkarte mit dem Standortpunkt, rechts unten im
   Hero auf der Inhaltskante. Umriss als Linie im Akzent, der Punkt
   pulsiert leise (nicht bei prefers-reduced-motion). Auf schmalen
   Bildschirmen weg - dort ist der Hero voll mit Text. */
.np-hero__karte {
    position: absolute;
    right: var(--gutter, 24px);
    bottom: 40px;
    width: clamp(150px, 15vw, 215px);
    margin: 0;
    pointer-events: none;
}
.np-hero__karte svg { display: block; width: 100%; height: auto; overflow: visible; }
.np-hero__karte-land {
    fill: color-mix(in srgb, var(--color-accent) 10%, transparent);
    stroke: var(--color-accent-300);
    stroke-width: 1.2px;
    stroke-linejoin: round;
}
.np-hero__karte-punkt { fill: var(--color-accent); stroke: var(--color-bg); stroke-width: 1.5px; }
.np-hero__karte-puls { fill: none; stroke: var(--color-accent); stroke-width: .6; transform-box: fill-box; transform-origin: center; animation: np-karte-puls 2.4s ease-out infinite; }
/* 4.2 sind Einheiten der SVG-Zeichnung, keine Pixel: die Schrift waechst
   mit der Karte. Deshalb hier kein --text-Token. */
.np-hero__karte-name { font-family: var(--font-body); font-size: 4.2px; font-weight: 600; fill: var(--color-text); paint-order: stroke; stroke: var(--color-bg); stroke-width: 1.2px; stroke-linejoin: round; }
@keyframes np-karte-puls {
    0%   { transform: scale(1);   opacity: .9; }
    100% { transform: scale(3.2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .np-hero__karte-puls { animation: none; opacity: 0; } }
/* Auf schmalen Bildschirmen wandert die Karte in den Hintergrund: groesser,
   halb durchsichtig, rechts hinter dem Text (z-index -1 innerhalb des
   isolierten Heros: ueber Foto und Schleier, unter der Schrift). Der
   Name faellt weg - der Kicker nennt den Standort ohnehin. */
@media (max-width: 820px) {
    /* Die angeschnittene Karte darf die Seite nicht breiter machen -
       sonst laesst sich der Hero seitwaerts scrollen. */
    .np-hero { overflow: hidden; }
    /* Die Karte sitzt am unteren Rand des Heros, nicht am oberen: hinter
       Ueberschrift und Fliesstext war sie unruhig, hinter Knoepfen und
       Eckdaten ist sie Hintergrund. Der Bezug auf den unteren Rand haelt
       sie bei jeder Hoehe des Heros an derselben Stelle - der waechst mit
       der Fensterhoehe.

       Schmaler als frueher und ganz im Hero statt angeschnitten: auf dem
       Telefon nahm sie sonst die halbe Flaeche ein. */
    .np-hero__karte {
        right: -6vw;
        top: auto;
        bottom: 10px;
        width: clamp(165px, 46vw, 240px);
        opacity: .45;
        z-index: -1;
    }
    .np-hero__karte-land { fill: color-mix(in srgb, var(--color-accent) 14%, transparent); stroke-width: 1px; }
    .np-hero__karte-name { display: none; }
}
/* Der Slogan war mit bis zu 84 px die lauteste Stelle der Seite und
   drueckte alles darunter - Untertitel, Knoepfe, Kennzahlen - in den
   Hintergrund. Jetzt rund ein Drittel kleiner: gross genug, um als
   erstes gelesen zu werden, klein genug, dass der Blick weiterwandert.
   Die 14ch bleiben: Textbreite und ch skalieren beide mit der
   Schriftgroesse, der Umbruch bleibt also derselbe wie vorher - eine
   Zeile am Schreibtisch, zwei auf dem Telefon. */
.np-hero__slogan {
    font-size: var(--text-display);
    max-width: 14ch;
}
.np-hero__points {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-6);
    margin-top: var(--space-8);
    color: var(--color-neutral-300);
    font-size: var(--text-sm);
}
.np-hero__points span { display: inline-flex; align-items: center; gap: var(--space-2); }
.np-hero__cta { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-6); }

/* ---------- Startseite: Kennzahlenband ----------
   Laeuft von Gelb nach Cyan - die lauteste Flaeche der Seite, und der
   Ort, an dem beide Hausfarben zusammen auftreten. */
.np-stats {
    background:
        linear-gradient(120deg,
            var(--color-section) 0%,
            var(--color-section-glow) 52%,
            color-mix(in srgb, var(--color-section-ghost) 55%, var(--color-section-glow)) 100%);
    border-block: 1px solid color-mix(in srgb, var(--color-accent) 20%, transparent);
    padding: var(--space-12) 0;
    margin: var(--space-2) 0;
}
.np-stats ul {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--space-8);
    margin: 0;
    padding: 0;
    list-style: none;
}
.np-stat__value {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-3xl);
    line-height: 1;
    font-variant-numeric: tabular-nums;
    color: var(--color-neutral-100);
}
.np-stat__label {
    margin-top: var(--space-2);
    font-size: var(--text-sm);
    color: var(--color-accent-200);
}

/* ---------- Startseite: Herstellerband ----------
   Die Marken laufen langsam von rechts nach links durch. Zwei gleiche
   Listen nebeneinander, jede mindestens so breit wie das Band; beide
   wandern um ihre eigene Breite plus Abstand nach links. Ist die erste
   hinaus, steht die zweite genau am Anfang - kein Sprung, kein JS.

   Logos und Namen sind einheitlich hell und gedimmt: das Band soll
   Vertrauen geben, nicht mit dem Hero um Aufmerksamkeit kaempfen. Die
   Raender blenden weich aus (mask-image), damit nichts hart abreisst.

   Mit Maus oder Fokus darueber haelt es an. Bei prefers-reduced-motion
   steht es still, und die Marken stehen mittig, notfalls umbrechend. */
.np-brands {
    --brands-gap: var(--space-16);
    --brands-dauer: 32s;
    padding-top: var(--space-12);
}
.np-brands__title {
    margin: 0 0 var(--space-6);
    text-align: center;
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--color-neutral-400);
}
.np-brands__viewport {
    display: flex;
    gap: var(--brands-gap);
    overflow: hidden;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
            mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
}
.np-brands__list {
    flex-shrink: 0;
    min-width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-around;
    gap: var(--brands-gap);
    margin: 0;
    padding: 0;
    list-style: none;
    animation: np-brands-lauf var(--brands-dauer) linear infinite;
}
.np-brands__viewport:hover .np-brands__list,
.np-brands__viewport:focus-within .np-brands__list { animation-play-state: paused; }

@keyframes np-brands-lauf {
    to { transform: translateX(calc(-100% - var(--brands-gap))); }
}

.np-brands__item {
    display: flex;
    align-items: center;
    height: 56px;
    flex-shrink: 0;
}
/* Einheitlich hell: jede Farbe wird zu Weiss, dann gedimmt. Setzt
   Logos mit transparentem Grund voraus (img/brands/LIESMICH.md). */
.np-brands__logo {
    display: block;
    height: 36px;
    width: auto;
    max-width: 180px;
    object-fit: contain;
    filter: brightness(0) invert(1);
    opacity: .6;
    transition: opacity .2s ease;
}
/* Solange kein Logo da ist: der Name als ruhige Wortmarke in der
   Hausschrift - kein Nachbau des Herstellerlogos. */
.np-brands__name {
    font-family: var(--font-heading);
    font-weight: var(--weight-heading);
    font-size: var(--text-xl);
    letter-spacing: .02em;
    white-space: nowrap;
    color: var(--color-neutral-300);
    opacity: .75;
    transition: opacity .2s ease, color .2s ease;
}
.np-brands__item:hover .np-brands__logo { opacity: 1; }
.np-brands__item:hover .np-brands__name { opacity: 1; color: var(--color-text); }

.np-brands__note {
    margin: var(--space-4) auto 0;
    max-width: 60ch;
    font-size: var(--text-xs);
    color: var(--color-neutral-500);
}

@media (max-width: 640px) {
    .np-brands { --brands-gap: var(--space-10); --brands-dauer: 24s; }
    .np-brands__logo { height: 28px; max-width: 130px; }
    .np-brands__name { font-size: var(--text-lg); }
}

@media (prefers-reduced-motion: reduce) {
    .np-brands__viewport {
        -webkit-mask-image: none;
                mask-image: none;
    }
    .np-brands__list {
        animation: none;
        flex-wrap: wrap;
        justify-content: center;
        row-gap: var(--space-4);
        column-gap: var(--space-10);
    }
    .np-brands__list[aria-hidden="true"] { display: none; }
    .np-brands__logo,
    .np-brands__name { transition: none; }
}

/* ---------- Kategoriekachel ---------- */
.np-cat {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    align-items: flex-start;
    text-align: left;
    padding: var(--space-4);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    border: 1px solid transparent;
    box-shadow: var(--shadow-sm);
    color: var(--color-text);
    font: inherit;
    cursor: pointer;
}
.np-cat:hover {
    text-decoration: none;
    color: var(--color-text);
    border-color: color-mix(in srgb, var(--color-accent) 50%, transparent);
    background: color-mix(in srgb, var(--color-accent) 7%, var(--color-surface));
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 40%, transparent),
                0 10px 34px -12px color-mix(in srgb, var(--color-accent) 55%, transparent);
}
.np-cat .icon { color: var(--color-accent); transition: transform .25s, filter .25s; }
.np-cat:hover .icon {
    transform: translateY(-2px);
    filter: drop-shadow(0 0 10px color-mix(in srgb, var(--color-accent) 70%, transparent));
}

/* ---------- Ablauf in vier Schritten ---------- */
/* Die Schrittnummer ordnet die vier Bloecke - sie darf man aus dem
   Augenwinkel lesen koennen, nicht erst beim Hinsehen. Expansiva in
   32 px statt 14, eng gestellt: die Schrift laeuft von sich aus weit. */
.np-flow__num {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: var(--text-3xl);
    line-height: 1;
    letter-spacing: -.02em;
    color: var(--color-accent);
}
.np-flow .np-rule { margin: var(--space-3) 0 var(--space-4); }
.np-flow .icon { color: var(--color-neutral-400); }

/* Nummer und Zeichnung in einer Zeile: die Ziffer links, das Bild daneben
   im verbleibenden Platz. Beide mittig zueinander, damit die Zeile eine
   gemeinsame Achse hat und die Ziffer nicht am Boden klebt. */
.np-flow__kopf {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    min-height: 112px;
}
/* Die vier Vorlagen haben unterschiedliche Seitenverhaeltnisse. Eine
   feste Hoehe und object-fit lassen sie trotzdem gleich gross wirken;
   links ausgerichtet, damit sie alle im selben Abstand neben der Ziffer
   beginnen. */
.np-flow__bild {
    display: block;
    flex: 1 1 auto;
    min-width: 0;
    height: 112px;
    object-fit: contain;
    object-position: left center;
}

/* ---------- Zitat ---------- */
.np-quote { margin: var(--space-8) 0 0; max-width: 760px; }
.np-quote p {
    font-size: var(--text-2xl);
    line-height: 1.3;
    color: var(--color-text);
    margin: 0;
}
.np-quote footer { margin-top: var(--space-4); font-size: var(--text-sm); color: var(--color-neutral-400); }

/* ---------- Abschluss-Aufruf ----------
   Text links, Foto rechts. Das Foto traegt hier keine Information, es
   setzt den Ton - deshalb steht es hinter dem Text in der Lesefolge. */
.np-cta {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.62fr);
    align-items: center;
    gap: var(--space-8);
    padding: var(--space-8);
    background: linear-gradient(140deg, var(--color-neutral-900), var(--color-surface));
}
.np-cta h2, .np-cta p { max-width: 520px; }
.np-cta .np-media { align-self: stretch; min-height: 200px; }

/* ---------- Abschluss-Aufruf mit Foto darunter ----------
   Dieselbe Karte, aber das Foto liegt unter der ganzen Flaeche statt
   daneben. Drei Lagen: Foto, Schleier, Text. Der Schleier ist kein
   Schoenheitsmittel, sondern die Bedingung dafuer, dass Schrift auf
   einem Foto lesbar bleibt - er ist links dicht und laeuft nach rechts
   aus, dorthin, wo nur noch Bild steht.

   Das Raster der Fassung darueber gilt hier nicht: es gibt nur eine
   Spalte, der Text sitzt darin und nimmt hoechstens die halbe Breite -
   sonst laeuft er ueber das Bild hinweg statt davor. */
.np-cta--foto {
    position: relative;
    display: block;
    overflow: hidden;
    padding: clamp(var(--space-6), 4.4vw, var(--space-16));
    min-height: 360px;
    background: var(--color-neutral-900);
}
.np-media--fuellend {
    position: absolute;
    inset: 0;
    z-index: 0;
    aspect-ratio: auto;
    border-radius: inherit;
}
.np-cta--foto::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    background:
        linear-gradient(100deg,
            color-mix(in srgb, var(--color-bg) 96%, transparent) 0%,
            color-mix(in srgb, var(--color-bg) 92%, transparent) 38%,
            color-mix(in srgb, var(--color-bg) 62%, transparent) 62%,
            color-mix(in srgb, var(--color-bg) 22%, transparent) 88%,
            color-mix(in srgb, var(--color-bg) 10%, transparent) 100%);
}
.np-cta--foto .np-cta__text {
    position: relative;
    z-index: 2;
    max-width: 560px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: inherit;
}
/* Eine Stufe groesser als die uebrigen Zwischenueberschriften: dieser
   Satz ist der letzte vor dem Fuss und darf auf dem Foto auftreten. */
.np-cta--foto h2 { font-size: var(--text-h1); }
.np-cta--foto .np-muted { color: var(--color-neutral-200); }

/* ---------- Artikelkarte ---------- */
.np-item {
    position: relative;
    height: 100%;
    transition: box-shadow .15s, transform .15s;
}
.np-item:hover {
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent) 38%, transparent),
                0 16px 40px -18px color-mix(in srgb, var(--color-accent) 60%, transparent);
    transform: translateY(-3px);
}
/* Die ganze Karte ist anklickbar - der Link darin spannt sich darueber.
   Knoepfe in der Karte bekommen z-index und bleiben dadurch bedienbar. */
.np-item__link::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
}
.np-item__link { color: inherit; }
.np-item__link:hover { color: inherit; text-decoration: none; }
.np-item__foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: auto;
    padding-top: var(--space-2);
    position: relative;
    z-index: 1;
}
/* Preis und Knopf brechen beide nicht um. Wird die Karte zu schmal
   (dreistelliger Preis, "Gemerkt (2x)"), rutscht der Knopf in die naechste
   Zeile statt ueber den Kartenrand - und bleibt dort rechts stehen. */
.np-item__foot > :last-child { margin-left: auto; }

/* ---------- Artikelzeile (Listenansicht, Warenkorb) ---------- */
.np-listrow {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
}
.np-listrow:hover { background: color-mix(in srgb, var(--color-accent) 6%, var(--color-surface)); }
/* Flach: Zeilen, die schon in einer Karte stehen (geteilte Liste). Keine
   eigene Flaeche und kein Schatten - sonst Kasten im Kasten -, kein
   seitlicher Innenabstand, dafuer eine feine Linie zwischen den Zeilen. */
.np-listrow--flach {
    padding: var(--space-3) 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
}
.np-listrow--flach:hover { background: transparent; }
.np-listrow--flach + .np-listrow--flach { border-top: 1px solid var(--color-divider); }
.np-zeilen { display: flex; flex-direction: column; }
.np-listrow__media { width: 92px; height: 68px; flex: 0 0 auto; aspect-ratio: auto; }
.np-listrow__body { min-width: 0; flex: 1; }
.np-listrow__side { display: flex; align-items: center; gap: var(--space-3); flex: 0 0 auto; position: relative; z-index: 1; }

/* Ein Zusatzposten unter einer Position: Aufbau beim Artikel, die Fahrt
   am Ende der Liste. Eingerueckt und leiser als die Position selbst - er
   gehoert dazu, steht aber nicht auf derselben Stufe. Der Rand links
   zeigt die Zugehoerigkeit, ohne eine zweite Linie zu ziehen. */
.np-listrow--zusatz {
    margin-left: var(--space-6);
    padding: var(--space-2) var(--space-4);
    gap: var(--space-3);
    background: transparent;
    box-shadow: none;
    border-left: 2px solid color-mix(in srgb, var(--color-text) 14%, transparent);
    border-radius: 0 var(--radius-md) var(--radius-md) 0;
    color: var(--color-neutral-400);
    font-size: var(--text-sm);
}
.np-listrow--zusatz:hover { background: transparent; }
.np-listrow--zusatz .icon { color: var(--color-accent-300); flex: 0 0 auto; }
.np-listrow--zusatz .np-price { font-size: var(--text-base); color: var(--color-neutral-300); }

/* Eine Fahrt gehoert zu keinem einzelnen Artikel, sondern zum ganzen
   Korb. Darum ohne Einzug und ohne den Rand, der Zugehoerigkeit zeigt. */
.np-listrow--gesamt {
    margin-left: 0;
    border-left: 0;
    border-radius: 0;
}

/* Die feine Linie darueber setzt den korbweiten Teil von den Artikeln ab.
   Sie traegt nur die ERSTE dieser Zeilen - stuende sie auch zwischen
   Hinweg und Rueckweg, trennte sie zwei Dinge, die zusammengehoeren. */
.np-listrow--abgesetzt {
    border-top: 1px solid var(--color-divider);
    padding-top: var(--space-3);
    margin-top: var(--space-1);
}

@media (max-width: 480px) {
    .np-listrow--zusatz { margin-left: var(--space-3); }
}

/* ---------- Katalog ---------- */
.np-catalog {
    display: grid;
    grid-template-columns: 196px minmax(0, 1fr);
    gap: var(--space-8);
    align-items: start;
}
.np-catalog__aside { position: sticky; top: 88px; }
.np-catalog__aside ul {
    display: flex;
    flex-direction: column;
    gap: var(--space-05);
    margin: var(--space-2) 0 0;
    padding: 0;
    list-style: none;
}
/* Jede Kategorie mit ihrem Symbol (Spalte kategorien.icon), "Alles" mit
   der Liste. Das Symbol bleibt leise und leuchtet erst bei Auswahl oder
   Hover in der Akzentfarbe. */
.np-catalog__aside .np-navlink {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}
.np-catalog__aside .np-navlink .icon { width: 17px; height: 17px; color: var(--color-neutral-500); }
/* Oberkategorien in der Seitenleiste (nur ab der zweiten): der Gruppen-
   Link steht wie eine kleine Ueberschrift, die Unterkategorien eingerueckt. */
.np-catalog__gruppe { margin-top: var(--space-3); }
.np-catalog__gruppe:first-of-type { margin-top: var(--space-1); }
.np-navlink--gruppe { font-size: var(--text-sm); font-weight: 700; color: var(--color-neutral-300); }
.np-catalog__unter .np-navlink { padding-left: var(--space-6); }
/* Dasselbe auf der Startseite: eine Zwischenueberschrift je Gruppe. */
.np-cats__gruppe { margin: var(--space-6) 0 var(--space-3); font-size: var(--text-sm); font-weight: 600; color: var(--color-neutral-300); }
.np-cats__gruppe a { display: inline-flex; align-items: center; gap: var(--space-2); text-decoration: none; color: inherit; }
.np-cats__gruppe .icon { color: var(--color-accent); }
.np-cats__gruppe + .np-grid--cats { margin-top: 0; }
.np-catalog__aside .np-navlink:hover .icon,
.np-catalog__aside .np-navlink.on .icon { color: var(--color-accent); }

/* Werkzeuge in der Kopfzeile des Katalogs: Suche, Anzahl, Sortierung.
   Die Suche steht vorn und darf auf schmalen Bildschirmen in eine
   eigene Zeile umbrechen; das Feld bleibt dabei kompakt. */
/* Die Kopfzeile darueber braucht weniger Luft, die Werkzeugzeile setzt
   den Abstand zum Raster. */
.np-catalog .np-sec-head { margin-bottom: var(--space-4); }
.np-catalog__werkzeuge { row-gap: var(--space-3); margin-bottom: var(--space-6); }
.np-catalog__suche .input { width: 200px; min-width: 0; }
.np-catalog__suche { flex: 0 1 auto; }

/* ---------- Artikelseite ---------- */
.np-product {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr);
    gap: var(--space-10);
    margin-top: var(--space-4);
}
/* Der Film des Artikels spielt im grossen Rahmen, im selben 4:3 wie die
   Fotos, damit beim Umschalten nichts springt. Ein Film in 16:9 bekommt
   schwarze Balken oben und unten (contain). main.js setzt .is-film am
   Rahmen und blendet das Foto dafuer aus. */
.np-product__film {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: contain;
    border-radius: var(--radius-lg);
    background: var(--color-film);
}
.np-product__film[hidden] { display: none; }
.np-product__bild.is-film > .np-media { display: none; }

/* Play-Knopf mittig auf der Film-Miniatur im Streifen. */
.np-product__play {
    position: absolute;
    inset: 0;
    margin: auto;
    pointer-events: none;
}

/* ---------- YouTube-Videos (Artikelseite, vor den Fragen) ----------
   Eine Kachel je Video: die Bildflaeche .np-media in 16:9, darin ein
   Link ueber die ganze Flaeche mit dem Vorschaubild und dem gelben
   Hauptknopf in der Mitte. Nach dem Klick setzt main.js den Player
   (iframe) an dieselbe Stelle - Groesse und Rundung bleiben, nichts
   springt. Darunter Titel und der Hinweis, dass erst der Klick YouTube
   laedt.

   min(300px, 100%): auf einem 320 px schmalen Telefon waere eine feste
   Mindestbreite breiter als die Spalte und schoebe die Seite seitlich. */
.np-grid--videos { grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr)); }
.np-yt {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin: 0;
}
.np-yt__start {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
}
.np-yt__start img {
    position: absolute;
    inset: 0;
    opacity: .75;
    transition: opacity .2s;
}
.np-yt__start:hover img { opacity: 1; }
/* Der Rahmen schneidet alles ab, was uebersteht (.np-media hat
   overflow: hidden) - der Fokusring liegt deshalb innen. */
.np-yt__start:focus-visible { outline-offset: calc(-1 * var(--space-1)); }
.np-yt__knopf { position: relative; }
.np-yt iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}
.np-yt__text {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
/* Das grosse Foto mit dem Lade-Kreis darueber. Beim Wechsel blendet das
   Bild aus (.is-wechsel setzt main.js, 5a); der Kreis erscheint erst nach
   einer Pause - kommt das Foto aus dem Cache, sieht man ihn nie. Die
   Dauer des Ausblendens steht auch in main.js (AUSBLENDEN_MS). */
.np-product__bild { position: relative; }
.np-product__bild picture { transition: opacity .2s ease; }
.np-product__bild.is-wechsel picture { opacity: 0; }
.np-product__bild > .np-lader {
    position: absolute;
    inset: 0;
    margin: auto;
    opacity: 0;
    pointer-events: none;
    transition: opacity .15s ease;
}
.np-product__bild.is-wechsel > .np-lader {
    opacity: 1;
    transition-delay: .35s;
}
@media (prefers-reduced-motion: reduce) {
    .np-product__bild picture { transition: none; }
}

/* Der Streifen unter dem grossen Foto: vier Miniaturen sichtbar, der Rest
   seitlich zu scrollen (Wischen, Rollbalken, Pfeiltasten im Fokus). Das
   Hauptfoto steht immer vorne. Unten etwas Luft, damit der Rollbalken
   die Bilder nicht anschneidet. */
.np-product__streifen {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-2);
}
.np-product__thumbs {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    gap: var(--space-2);
    padding-bottom: var(--space-2);
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: thin;
    scrollbar-color: var(--color-neutral-600) transparent;
}
/* Mit Maus (main.js setzt .has-pfeile): links und rechts ein Pfeil statt
   des Rollbalkens. Am Anfang bzw. Ende ist der jeweilige Pfeil
   abgeschaltet (disabled, gedaempft vom Baustein). Ohne JavaScript und
   auf Touch-Geraeten bleibt der Rollbalken. */
.np-product__pfeil { flex: 0 0 auto; }
.np-product__streifen.has-pfeile .np-product__thumbs {
    padding-bottom: 0;
    scrollbar-width: none;
}
.np-product__streifen.has-pfeile .np-product__thumbs::-webkit-scrollbar { display: none; }
/* Die Miniaturen sind Links: ohne JavaScript oeffnen sie das Foto, mit
   JavaScript tauschen sie das grosse Bild. Die gerade gezeigte traegt
   aria-current und einen Rahmen im Akzent, die anderen sind gedaempft.
   Der Rahmen liegt innen und als eigene Ebene (::after) ueber dem Bild:
   der Streifen scrollt seitlich und schneidet alles ab, was ueber den
   Rand ragt, und das positionierte .np-media wuerde einen Rahmen am
   Link selbst ueberdecken. Deshalb auch kein Anheben beim Ueberfahren. */
.np-product__thumb {
    position: relative;
    flex: 0 0 calc((100% - 3 * var(--space-2)) / 4);
    display: block;
    border-radius: var(--radius-md);
    overflow: hidden;
    scroll-snap-align: start;
    opacity: .55;
    transition: opacity .15s;
    /* Das Foto sitzt eingerueckt: zwischen Rahmen und Bild bleibt ein
       dunkler Spalt. Ohne ihn verschwindet der gelbe Rahmen auf Fotos mit
       weissem Grund. Das Foto hat die Rundung von .np-media (radius-sm),
       eine Stufe kleiner als der Rahmen - so wirkt der Spalt rundum
       gleich breit. */
    padding: var(--space-1);
}
.np-product__thumb::after {
    content: "";
    position: absolute;
    inset: 0;
    border: 2px solid transparent;
    border-radius: inherit;
    pointer-events: none;
    transition: border-color .15s;
}
.np-product__thumb:hover,
.np-product__thumb:focus-visible { opacity: .85; }
.np-product__thumb[aria-current="true"] { opacity: 1; }
.np-product__thumb[aria-current="true"]::after { border-color: var(--color-accent); }
/* Der allgemeine Fokusring liegt aussen und waere im Streifen
   abgeschnitten - hier zeigt ihn dieselbe innere Ebene, im zweiten
   Akzent, damit er sich vom "gerade gezeigt" unterscheidet. */
.np-product__thumb:focus-visible { outline: 2px solid var(--color-accent2); outline-offset: -2px; }
.np-product__thumb:focus-visible::after { border-color: var(--color-accent2); }

/* ==================================================================
   Ausfuehrungen (Varianten)

   Der Punkt traegt die Farbe. Er ist bewusst gross genug, um sie
   wirklich zu zeigen - ein 8-px-Pixel waere eine Behauptung, keine
   Farbprobe. Die Farbe kommt aus dem SVG (VariantSwatch in
   phpfunctions.php); hier stehen nur Groesse und Form.
   ================================================================== */
.np-swatch {
    display: inline-block;
    width: 22px;
    height: 22px;
    flex: 0 0 auto;
    border-radius: 50%;
    overflow: hidden;
}
.np-swatch--foto { background: var(--color-neutral-800); }
.np-swatch--foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Ohne Farbe und ohne Foto: ein schraffierter Punkt. Er sagt "hier fehlt
   etwas", statt sich als graue Ausfuehrung auszugeben. */
.np-swatch--leer {
    background: repeating-linear-gradient(45deg,
        var(--color-neutral-700) 0 3px, var(--color-neutral-800) 3px 6px);
}
.np-swatch--mini { width: 14px; height: 14px; }

/* ---------- Die Punktreihe auf der Katalogkarte ----------
   Sie liegt ueber der Flaeche, die der Titel-Link aufspannt - sonst
   fuehrte jeder Klick auf eine Farbe doch nur zum Artikel ohne Farbe. */
.np-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1);
    margin: 0 0 var(--space-2);
    padding: 0;
    list-style: none;
    position: relative;
    z-index: 1;
}
.np-swatches__link {
    display: block;
    padding: var(--space-05);
    border-radius: 50%;
    transition: transform .12s;
}
.np-swatches__link:hover { transform: scale(1.12); }
.np-swatches .np-swatch { width: 18px; height: 18px; }

/* ---------- Die Auswahl auf der Artikelseite ----------
   Knoepfe mit Farbe UND Wort. Nur der Punkt waere fuer jemanden mit
   Farbsehschwaeche keine Auswahl, nur das Wort keine Farbprobe. */
.np-varianten__liste {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: var(--space-2) 0 0;
    padding: 0;
    list-style: none;
}
.np-varianten__knopf {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: var(--space-2) var(--space-3) var(--space-2) var(--space-2);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
    color: var(--color-text);
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1.2;
    transition: box-shadow .15s, transform .15s;
}
.np-varianten__knopf:hover {
    text-decoration: none;
    color: var(--color-text);
    transform: translateY(-1px);
}
/* Die gewaehlte Ausfuehrung traegt den Akzentrahmen. Kein gefuelltes
   Gelb: die Flaeche daneben gehoert dem Farbpunkt, und zwei kraeftige
   Farben nebeneinander machen beide unleserlich. */
.np-varianten__knopf.is-active {
    box-shadow: 0 0 0 2px var(--color-accent), var(--shadow-sm);
}
.np-note--klein { font-size: var(--text-sm); margin-top: var(--space-2); }

/* Der Weg zur Auswahl auf der Katalogkarte. Er steht anstelle des
   Merken-Knopfes und traegt ein laengeres Wort - ohne diese Bremse
   schoebe er den Preis daneben zusammen, bis er umbricht. */
.np-item__waehlen { white-space: nowrap; }
.np-item__foot .np-price { white-space: nowrap; }

/* ---------- Die Ausfuehrung in Korb und Merkliste ---------- */
.np-variante {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* "ab" ueber dem Preis, wenn es mehrere Ausfuehrungen gibt. Kleiner und
   ruhiger als die Zahl - es ist eine Einschraenkung, keine Ansage.
   Und ueber statt vor der Zahl: in einer Zeile waere "ab 89 EUR / Tag"
   neben dem Knopf so lang, dass die Zeile umbricht und der Preis
   auseinanderfaellt. */
.np-price__ab {
    display: block;
    font-size: var(--text-sm);
    font-weight: 600;
    line-height: 1;
    color: var(--color-neutral-400);
}
.np-product__specs {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}
.np-product__specs li { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-base); }
.np-product__buy {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
}
.np-product__price { font-family: var(--font-display); font-weight: 700; font-size: var(--text-2xl); line-height: 1.1; }

/* ---------- Pakete ---------- */
.np-pack { padding: var(--space-5); gap: var(--space-2); border-top: 1px solid transparent; }
.np-pack--featured { border-top-color: var(--color-accent); }
.np-pack ul {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}
.np-pack li { display: flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); }
.np-pack__price { display: flex; align-items: baseline; gap: var(--space-2); margin-top: var(--space-2); }
.np-pack__price .np-price { font-size: var(--text-2xl); font-variant-numeric: tabular-nums; }

/* ---------- Anfrage ---------- */
.np-request {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 290px;
    gap: var(--space-6);
    margin-top: var(--space-6);
    align-items: start;
}
.np-summary { position: sticky; top: 88px; }
.np-sum {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    font-size: var(--text-base);
}
.np-sum__row { display: flex; justify-content: space-between; gap: var(--space-4); }
/* Position mit Foto (pages/page-offer.php): Bild wie im Warenkorb
   (.np-media--mini), daneben der Name. Positionen ohne Foto bekommen einen
   leeren Platz in derselben Breite, damit die Namen buendig stehen. Die
   Zeile mittig, damit der Betrag rechts auf Hoehe des Namens steht. */
.np-sum__row:has(> .np-sum__item) { align-items: center; }
.np-sum__item { display: flex; align-items: center; gap: var(--space-3); min-width: 0; }
.np-sum__platz { width: 52px; flex: 0 0 auto; }
@media (max-width: 480px) {
    .np-sum__platz { width: 44px; }
}

/* GiroCode zum Bezahlen (pages/page-offer.php nach der Annahme). Weisser
   Grund auch im dunklen Design - Banking-Apps lesen nur dunkel auf hell.
   Groesse wie .admin-qr im Admin, nur etwas kleiner fuer zwei nebeneinander. */
.np-qr {
    display: block;
    width: 200px;
    max-width: 100%;
    height: auto;
    margin: var(--space-3) auto;
    border-radius: var(--radius-md);
    background: var(--color-qr-grund);
}

/* Je Zahlweg eine Karte, mittig: Ueberschrift, Betrag gross, Code,
   Verwendungszweck. Der Betrag in der Groesse einer h2 - er ist das, was
   der Kunde vor dem Scannen sicher wissen muss. */
.np-zahlweg { text-align: center; }
.np-zahlweg__betrag {
    margin: 0;
    font-size: var(--text-2xl);
    font-weight: 700;
    color: var(--color-text);
}
/* Angaben zum Abtippen, Bezeichnung ueber dem Wert (Bankverbindung auf
   der Angebotsseite). Lange Werte wie IBAN oder Verwendungszweck brechen
   um, statt aus der Karte zu laufen. */
.np-angaben { display: grid; gap: var(--space-3); margin: var(--space-4) 0 0; }
.np-angaben dt { font-size: var(--text-sm); color: var(--color-neutral-400); }
.np-angaben dd { margin: 0; color: var(--color-text); overflow-wrap: anywhere; }

.np-sum__row span:first-child { color: var(--color-neutral-400); }
/* Betraege und Werte rechts bleiben auf einer Zeile ("20,00 €" nie
   umbrochen); umbrechen darf nur die Bezeichnung links. */
.np-sum__row > span:last-child { white-space: nowrap; }
.np-sum__total { font-family: var(--font-display); font-weight: 700; font-size: var(--text-xl); }

/* ---------- Kalender ---------- */
.np-cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: var(--space-1); }
.np-cal-h {
    font-size: var(--text-xs);
    color: var(--color-neutral-400);
    text-align: center;
    padding-bottom: var(--space-1);
}
.np-cal-d {
    aspect-ratio: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--color-divider);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text);
    font: inherit;
    font-size: var(--text-sm);
    cursor: pointer;
}
.np-cal-d:hover { border-color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 12%, transparent); }
.np-cal-d.warn { color: var(--color-neutral-500); }
.np-cal-d.off {
    background: var(--color-neutral-900);
    color: var(--color-neutral-700);
    border-color: transparent;
    cursor: not-allowed;
    text-decoration: line-through;
}
.np-cal-d.on { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-bg); }
/* Ein Tag ist ein Label mit Radio darin - dadurch waehlt der Kalender
   auch ohne JavaScript aus, und die Auswahl geht mit dem Formular mit. */
.np-cal-d input { position: absolute; opacity: 0; pointer-events: none; }
label.np-cal-d:has(input:checked) {
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: var(--color-bg);
}
label.np-cal-d:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: 2px; }
/* Mietdauer laenger als ein Tag: die Folgetage des Zeitraums. Faellt einer
   auf einen gesperrten Tag, bleibt er durchgestrichen und bekommt den
   Rahmen - der Hinweis unter der Legende sagt, was zu tun ist. */
.np-cal-d--range {
    background: color-mix(in srgb, var(--color-accent) 22%, transparent);
    border-color: var(--color-accent);
    color: var(--color-text);
}
.np-cal-d.off.np-cal-d--range { outline: 2px solid var(--color-accent); outline-offset: -2px; }
.np-cal__hint { color: var(--color-accent-300); }
.np-cal__legend { display: flex; gap: var(--space-4); font-size: var(--text-xs); color: var(--color-neutral-400); flex-wrap: wrap; }
.np-dot { width: 7px; height: 7px; border-radius: var(--radius-pill); display: inline-block; }
.np-dot--frei   { background: var(--color-accent); }
.np-dot--knapp  { background: var(--color-neutral-600); }
.np-dot--belegt { background: var(--color-neutral-800); }

/* ---------- FAQ ----------
   <details> statt JavaScript: klappt auch ohne Skript auf und ist fuer
   Suchmaschinen im Quelltext vollstaendig lesbar. */
.np-faq { border-bottom: 1px solid var(--color-divider); }
.np-faq summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) 0;
    font-family: var(--font-heading);
    font-weight: 500;
    font-size: var(--text-lg);
    cursor: pointer;
    list-style: none;
}
.np-faq summary::-webkit-details-marker { display: none; }
.np-faq summary:hover { color: var(--color-accent-200); }
.np-faq summary .icon { color: var(--color-accent); transition: transform .2s; }
.np-faq[open] summary .icon { transform: rotate(180deg); }
.np-faq p { color: var(--color-neutral-300); padding: 0 0 var(--space-4); max-width: 620px; }

/* ---------- FAQ: Rubriken und Sprungmarken ----------
   Die Leiste oben ist kein Menue, sondern ein Inhaltsverzeichnis: sechs
   Anker auf derselben Seite. Sie steht als Umriss da und nicht in der
   Akzentfarbe - sonst konkurriert sie mit dem Anfrage-Knopf um die
   Aufmerksamkeit, und das ist eine Schlacht, die eine Inhaltsangabe
   nicht gewinnen soll. */
.np-faq__sprung {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin: var(--space-6) 0 var(--space-4);
}
.np-faq__sprungziel {
    padding: var(--space-2) var(--space-4);
    border: 1px solid color-mix(in srgb, var(--color-accent2) 45%, transparent);
    border-radius: var(--radius-pill);
    font-size: var(--text-sm);
    color: var(--color-neutral-300);
    text-decoration: none;
}
.np-faq__sprungziel:hover {
    border-color: var(--color-accent2);
    color: var(--color-text);
}
/* Erste Rubrik enger an die Sprungmarken, die uebrigen mit Luft davor -
   sonst laeuft eine Rubrik in die vorige. */
.np-faq__rubrik + .np-faq__rubrik { margin-top: var(--space-8); }
.np-faq__rubrik h2 { margin-bottom: var(--space-2); }

/* Auf dem Telefon stapeln sich sechs Rubriknamen sonst zu sechs Zeilen,
   und die erste Antwort steht erst unterhalb des Bildschirms. Kleiner
   gesetzt passen meist zwei nebeneinander - das halbiert die Leiste,
   ohne sie zu verstecken. Weglassen waere die schlechtere Loesung: auf
   dem langen Telefonbildschirm nuetzt ein Inhaltsverzeichnis am
   meisten. */
@media (max-width: 520px) {
    .np-faq__sprung { gap: var(--space-2); margin-top: var(--space-4); }
    .np-faq__sprungziel { padding: var(--space-1) var(--space-3); font-size: var(--text-xs); }
}

/* ---------- Info-Seiten ---------- */
.np-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, .85fr);
    gap: var(--space-12);
    align-items: start;
}
.np-split--even { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-10); }
.np-prose { max-width: 70ch; }
.np-prose h2 { margin-top: var(--space-8); }
/* Lange Woerter ("Datenschutzbeauftragter") passen bei 28 px auf dem Handy
   nicht in die Zeile, schon gar nicht mit groesserer Systemschrift.
   Deshalb dort eine Stufe kleiner; trennen darf der Browser als letzter
   Ausweg (lang="de" am <html>). */
.np-prose h2 { hyphens: auto; overflow-wrap: break-word; }
@media (max-width: 520px) {
    .np-prose h2 { font-size: var(--text-xl); }
}
/* Die Zeile darueber ist staerker als .card-title { margin: 0 } - der
   erste Kartentitel in np-prose (Registrieren, Widerrufsformular) stand
   deshalb 32 px tiefer als auf der Kontaktseite. Oben in der Karte
   sorgt das Padding fuer Luft; nur ein weiterer Abschnittstitel in
   derselben Karte ("Zugangsdaten") behaelt seinen Abstand. */
.np-prose .card-title { margin-top: 0; }
.np-prose .card-title ~ .card-title { margin-top: var(--space-8); }
.np-prose p, .np-prose li { color: var(--color-neutral-300); }

/* Die Zeile darueber ist staerker als .np-kicker: ".np-prose p" traegt
   eine Klasse UND ein Element, ".np-kicker" nur eine Klasse. Auf der
   FAQ-Seite - der einzigen mit np-prose UND Kicker - stand die Zeile
   "FAQ & Mietbedingungen" deshalb grau statt in der Hausfarbe, waehrend
   sie auf jeder anderen Seite leuchtet. Hier wird sie zurueckgeholt. */
.np-prose .np-kicker { color: var(--color-accent); }

/* Aus demselben Grund verloren Fehlermeldungen im Fliesstext ihre Farbe:
   ".np-prose p" ist staerker als ".field__error", und beide Meldungen
   sind Absaetze. Auf dem Widerrufsformular - der einzigen Seite mit
   np-prose UND Formular - stand der Fehler deshalb grau im roten Kasten,
   waehrend er bei der Newsletteranmeldung rot leuchtet. */
.np-prose .field__error,
.np-prose .notice--error { color: var(--color-fehler); }

/* Anschriften stehen im Fliesstext der Rechtsseiten (Verantwortlicher,
   Aufsichtsbehoerde, Empfaenger des Widerrufs). Ohne eigenen Abstand
   klebten sie am folgenden Absatz - address bringt von sich aus keinen
   mit. */
.np-prose address {
    color: var(--color-neutral-300);
    margin: var(--space-4) 0;
}

/* Ein Link im Fliesstext kann eine ganze Adresse sein: Die
   Widerrufsbelehrung muss die Internet-Adresse des Widerrufsformulars
   ausschreiben (Gestaltungshinweis 2 zu Anlage 1 EGBGB). Auf einem
   schmalen Telefon waere das sonst ein Wort, das die Seite breiter
   macht als den Bildschirm. break-word bricht nur, wenn es sein muss -
   kurze Links bleiben unangetastet. */
.np-prose a {
    overflow-wrap: break-word;
}

/* Tabelle im Fliesstext - bisher nur die Cookie-Liste in der
   Datenschutzerklaerung. Auf schmalen Bildschirmen darf sie scrollen,
   statt die Seite breit zu machen. */
.np-table__wrap {
    margin: var(--space-4) 0;
    overflow-x: auto;
}

.np-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--text-sm);
}
.np-table th,
.np-table td {
    padding: var(--space-3) var(--space-4) var(--space-3) 0;
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid var(--color-divider);
}
.np-table th { color: var(--color-neutral-400); font-weight: 600; white-space: nowrap; }
.np-table td { color: var(--color-neutral-300); }
.np-table code {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--text-sm);
    color: var(--color-text);
    white-space: nowrap;
}
.np-facts {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-5);
    margin-top: var(--space-6);
}
.np-facts dt { font-family: var(--font-display); font-weight: 700; font-size: var(--text-2xl); }
.np-facts dd { margin: 0; font-size: var(--text-sm); color: var(--color-neutral-500); }

.np-contactlist { display: flex; flex-direction: column; gap: var(--space-5); margin-top: var(--space-6); }
.np-contactlist > div { display: flex; gap: var(--space-4); align-items: flex-start; }
.np-contactlist .icon { width: 26px; height: 26px; color: var(--color-accent); margin-top: 1px; }

/* ---------- Baustellenseite ---------- */
.np-soon {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: var(--space-4);
    padding: var(--space-10) var(--gutter);
}
.np-soon img { width: min(420px, 80vw); height: auto; }


/* ==================================================================
   8. Umbrueche
   ================================================================== */

@media (max-width: 1000px) {
    .np-catalog,
    .np-product,
    .np-split,
    .np-split--even { grid-template-columns: minmax(0, 1fr); }
    .np-hero { min-height: clamp(440px, 60svh, 560px); }
    .np-hero__inhalt { padding-top: var(--space-16); padding-bottom: var(--space-8); }
    .np-product { gap: var(--space-8); }
    .np-split { gap: var(--space-8); }

    .np-navmain { display: none; }
    /* Das Menue rueckt ganz nach aussen, die Sprache davor. Auf dem
       Desktop steht die Sprache aussen, weil das Menue dort fehlt. */
    .np-burger { display: inline-flex; }
    .np-nav__actions > .np-menu { order: 10; }
    .np-catalog__aside { position: static; }
    .np-catalog__aside ul { flex-direction: row; flex-wrap: wrap; }
    /* Einspaltig soll die Ueberschrift ganz oben stehen, dann die
       Kategorien, dann Suche und Artikel. Die rechte Spalte loest sich
       dafuer in ihre Teile auf (display: contents), die das Raster in
       der gewuenschten Reihenfolge anordnet. Kein zweites Markup. */
    .np-catalog { gap: var(--space-5); }
    .np-catalog > div { display: contents; }
    .np-catalog .np-sec-head { order: 1; margin-bottom: 0; }
    .np-catalog__aside { order: 2; }
    .np-catalog__werkzeuge { order: 3; margin-bottom: var(--space-1); }
    .np-catalog [data-artikelliste] { order: 4; }
}

@media (max-width: 820px) {
    .np-request { grid-template-columns: minmax(0, 1fr); }
    .np-cta { grid-template-columns: minmax(0, 1fr); gap: var(--space-6); }
    /* Schmal nimmt der Text die ganze Breite ein. Der Schleier kann dann
       nicht mehr nach rechts auslaufen - dort steht jetzt auch Schrift.
       Er wird deshalb flaechig und laeuft nur noch leicht nach unten
       nach, damit das Foto oben durchkommt. */
    .np-cta--foto { min-height: 300px; }
    .np-cta--foto .np-cta__text { max-width: none; }
    .np-cta--foto::before {
        background:
            linear-gradient(180deg,
                color-mix(in srgb, var(--color-bg) 62%, transparent) 0%,
                color-mix(in srgb, var(--color-bg) 84%, transparent) 55%,
                color-mix(in srgb, var(--color-bg) 92%, transparent) 100%);
    }
    .np-summary { position: static; }
    .np-footgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .np-hide-sm { display: none; }
    /* In der Kopfleiste bleibt nur noch die Flagge - der Sprachname
       steht ausgeschrieben im Aufklappmenue. */
    .np-nav__actions > .np-sprache .np-sprache__text { display: none; }
    .np-nav__konto-text { display: none; }
    .np-quote p { font-size: var(--text-xl); }
}

@media (max-width: 520px) {
    .np-footgrid { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
    .np-facts { grid-template-columns: repeat(2, 1fr); }
    .np-cta { padding: var(--space-6); }
    /* Auf dem Foto braucht die Schrift etwas mehr Rand als auf einer
       ruhigen Flaeche, sonst klebt sie an der Bildkante. */
    .np-cta--foto { padding: var(--space-6) var(--space-5) var(--space-6); }
    .np-listrow { flex-wrap: wrap; }

    /* Anfrageseite: die Bloecke "1. Dein Equipment", "2. Termin" und
       "3. Kontakt" enthalten selbst wieder Karten - die Korbzeilen. Auf
       dem Telefon steht dann dreimal Abstand nebeneinander: 18 px
       Seitenrand, 24 px Karte, 14 px Zeile. Von 390 px bleiben so keine
       280 px fuer den Inhalt, und lange Artikelnamen brechen mitten im
       Wort um. Innen also schmaler - der Seitenrand bleibt, damit die
       Bloecke weiter als Bloecke zu erkennen sind. */
    .np-request .card--pad { padding: var(--space-4) var(--space-4); }
    .np-request .np-listrow { padding: var(--space-3); }
    /* Ganz schmal wird es im Kopf zu eng: der Umschalter steht dann nur
       noch im Aufklappmenue, wo er ohnehin ausgeschrieben ist. */
    .np-nav__actions > .np-sprache { display: none; }
    .np-nav__actions > .np-nav__konto { display: none; }
    /* Auf dem Handy stapelt sich die Fusszeile: dann stehen die
       Rechtslinks oben und das Copyright zuletzt. Auf dem Desktop
       bleibt es links neben den Links. */
    .np-foot__bottom { flex-direction: column; gap: var(--space-3); }
    .np-foot__bottom p:first-child { order: 2; }
}

@media print {
    .np-aurora, .np-nav, body::after { display: none !important; }
    body { color: var(--color-druck); }
}

/* ==================================================================
   Preisstaffel und Nebenkosten auf der Artikelseite

   Steht zwischen den Merkmalen und dem Anfrageknopf. Bewusst schlicht:
   eine Liste aus Bezeichnung und Betrag, keine Tabelle mit Rahmen -
   die Zahl soll sprechen, nicht das Gitter.
   ================================================================== */
/* Die Staffel ist zugeklappt (<details>), die Zeile zum Aufklappen sieht
   aus wie eine Zeile der Liste darunter: Text links, Pfeil rechts, der
   sich beim Oeffnen dreht - wie auf /faq. */
.np-staffel summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-top: 1px solid var(--color-divider);
    border-bottom: 1px solid var(--color-divider);
    font-size: var(--text-base);
    color: var(--color-text);
    cursor: pointer;
    list-style: none;
}
.np-staffel summary::-webkit-details-marker { display: none; }
.np-staffel summary:hover { color: var(--color-accent-200); }
.np-staffel summary .icon { color: var(--color-accent); transition: transform .2s; }
.np-staffel[open] summary .icon { transform: rotate(180deg); }
.np-staffel[open] summary { border-bottom: 0; }
@media (prefers-reduced-motion: reduce) {
    .np-staffel summary .icon { transition: none; }
}

.np-staffel ul,
.np-nebenkosten {
    list-style: none;
    margin: var(--space-2) 0 0;
    padding: 0;
    border-top: 1px solid var(--color-divider);
}

.np-staffel li,
.np-nebenkosten li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--color-divider);
    font-size: var(--text-base);
    color: var(--color-neutral-300);
}

.np-staffel strong,
.np-nebenkosten strong {
    font-family: var(--font-display);
    font-size: var(--text-base);
    font-weight: 400;
    color: var(--color-text);
}

/* Der Zusatz steht unter der Zeile, nicht daneben - sonst wird es auf
   schmalen Bildschirmen zu eng. */
.np-nebenkosten li { flex-wrap: wrap; }

.np-nebenkosten small {
    flex: 1 0 100%;
    font-size: var(--text-sm);
    color: var(--color-neutral-500);
}

.np-nebenkosten { margin-top: var(--space-4); }

/* ==================================================================
   Merkliste

   1. Die Marke "Gemerkt" auf der Katalogkarte und der Artikelseite.
   2. Die Schublade im Kopf: ein <details>, dessen Blatt von rechts
      hereinkommt. Wie das Aufklappmenue haengt es absolut am sticky
      .np-nav - der steht immer am oberen Rand, also wirkt das Blatt
      wie fixiert. position: fixed ginge hier nicht: backdrop-filter
      am Kopf macht ihn zum Bezug fuer fixierte Nachfahren.
   ================================================================== */
/* ---------- Merken ----------
   Der Merken-Knopf ist die Variante .btn-merken, der gemerkte Zustand
   .btn.is-saved - beide in css/bausteine.css. */

/* Die gemerkte Karte bekommt einen feinen Umriss im zweiten Akzent. */
.np-item.is-saved {
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--color-accent2) 60%, transparent);
}

/* Auf der Artikelseite legt der Knopf mit Menge dazu; den Stand zeigt
   eine schlichte Textzeile darunter. */
.np-product__saved { margin: 0; min-height: 0; }

/* ---------- Teilen (partials/share.php) ----------
   Artikelseite, Paketkarte, Anfrage und geteilte Liste. Ein Knopf, der
   eine Liste aufklappt - Aussehen vom Sprachumschalter (.np-sprache,
   css/bausteine.css). Hier nur, was beim Teilen anders ist: die Liste
   haengt links am Knopf, und zwei Eintraege sind Knoepfe statt Links.
   Auf der Paketkarte und unter der Positionsliste der Anfrage durch eine
   Linie abgesetzt - dort steht es unter einem anderen Inhalt. */
.np-share {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
    margin-top: var(--space-3);
}
.np-share .card-meta { margin: 0; }
.np-share__icon { color: var(--color-accent); }
.np-share__menue .np-sprache__liste { right: auto; left: 0; }
/* "Andere App" und "Link kopieren" sind <button> - aussehen wie die Links. */
.np-share__menue button.np-sprache__eintrag {
    width: 100%;
    border: 0;
    background: none;
    font-family: inherit;
    text-align: left;
    cursor: pointer;
}
.np-share__menue button.np-sprache__eintrag:hover {
    background: color-mix(in srgb, var(--color-text) 8%, transparent);
}
.np-pack .np-share,
[data-warenkorbzeilen] .np-share {
    padding-top: var(--space-4);
    border-top: 1px solid var(--color-neutral-800);
}

/* Das Paket, zu dem ein geteilter Link springt (#paket-...), faellt auf. */
.np-pack[id] { scroll-margin-top: var(--space-24); }
.np-pack:target { outline: 2px solid var(--color-accent); outline-offset: 4px; }
/* Gehoert zur Merkliste und traegt deshalb den zweiten Akzent. */
.np-saved {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--color-accent2-300);
    font-size: var(--text-sm);
}
.np-saved .icon { width: 14px; height: 14px; }
/* Eingeklappt: ohne diese Zeile gewinnt das display:inline-flex darueber
   gegen die Browserregel fuer [hidden], und "Gemerkt" stand unter JEDEM
   Artikel - auch unter denen, die gar nicht im Korb liegen. Dieselbe
   Falle wie bei .field[hidden] im Anfrageformular. */
.np-saved[hidden] { display: none; }

/* ---------- Schublade ---------- */
.np-drawer { position: static; }
.np-drawer summary { list-style: none; }
.np-drawer summary::-webkit-details-marker { display: none; }
.np-drawer__toggle { position: relative; padding-inline: var(--space-3); }

/* ---------- Login fuer Stammkunden ----------
   Neben der Merkliste. Mittel breit nur noch das Symbol, ganz schmal
   gar nicht - dort steht der Weg ausgeschrieben im Aufklappmenue. */
.np-nav__konto { padding-inline: var(--space-3); }

/* Beide liegen ueber allem im Kopf - auch ueber dem Sprachumschalter
   und dem Anfrage-Knopf, die im HTML NACH der Schublade kommen und
   sonst darueber gemalt wuerden. */
.np-drawer__backdrop {
    display: none;
    position: absolute;
    z-index: 60;
    left: 0;
    right: 0;
    top: 0;
    height: 100vh;
    height: 100dvh;
    background: var(--color-abdunkeln);
    cursor: pointer;
}

.np-drawer__panel {
    display: none;
    position: absolute;
    z-index: 61;
    top: 0;
    right: 0;
    width: min(400px, 100%);
    height: 100vh;
    height: 100dvh;
    flex-direction: column;
    background: var(--color-bg);
    border-left: 1px solid var(--color-divider);
    box-shadow: -24px 0 60px var(--color-schatten-tief);
    overflow-y: auto;
    overscroll-behavior: contain;
}

.np-drawer[open] .np-drawer__backdrop { display: block; }
.np-drawer[open] .np-drawer__panel { display: flex; animation: np-drawer-in .22s ease; }

/* Nur einblenden, nicht hereinschieben: ein Transform nach rechts
   verbreitert fuer einen Augenblick die Seite, und auf dem Handy
   liesse sie sich dann kurz waagerecht schieben. */
@keyframes np-drawer-in {
    from { transform: translateY(-6px); opacity: 0; }
    to   { transform: none; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .np-drawer[open] .np-drawer__panel { animation: none; }
}

.np-drawer__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-2);
    padding: var(--space-5) var(--space-5) var(--space-3);
    border-bottom: 1px solid var(--color-divider);
}
.np-drawer__head .np-kicker { margin: 0; }

.np-drawer__inhalt {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5) var(--space-6);
}


.np-drawer__list {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.np-drawer__row {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-3) var(--space-3);
    border-radius: var(--radius-md);
    background: var(--color-surface);
}
.np-drawer__row form { margin: 0; }
.np-drawer__top,
.np-drawer__bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}

/* Die Mengenwahl: dieselben Knoepfe wie auf der Anfrageseite, nur
   kleiner, damit die Zeile auf dem Handy in die Schublade passt. */
.np-drawer__qty { gap: var(--space-1); }
.np-drawer__qty input { width: 44px; height: 30px; font-size: var(--text-base); }
.np-drawer__body { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: var(--space-05); }
.np-drawer__name {
    color: inherit;
    text-decoration: none;
    font-weight: 500;
    font-size: var(--text-base);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.np-drawer__name:hover { color: var(--color-accent-300); }
.np-drawer__row .np-price { font-size: var(--text-base); flex: 0 0 auto; }

.np-drawer__sum {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-2);
    padding-top: var(--space-3);
    border-top: 1px solid var(--color-divider);
    font-size: var(--text-base);
}
.np-drawer__sum small { display: block; }
.np-drawer__sum .np-price { font-size: var(--text-xl); }

.np-drawer__foot { display: flex; flex-direction: column; gap: var(--space-2); }

/* ==================================================================
   Anfrageseite: Warenkorbzeile in zwei Reihen (wie die Merkliste) und
   der Kalender mit Blaettern
   ================================================================== */
.np-listrow--stack {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2);
}
.np-listrow__top,
.np-listrow__bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
}
.np-listrow--stack form { margin: 0; }
.np-listrow__bottom .np-price { flex: 0 0 auto; }

.np-cal__box { max-width: 460px; }
.np-cal__nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-2);
}
.np-cal__title { margin: 0; text-align: center; }
.np-cal__title:focus { outline: none; }
.np-cal__box[aria-busy="true"] .np-cal { opacity: .5; }

/* Betriebsferien: gesperrt wie "belegt", aber als eigener Grund
   erkennbar - schraffiert statt durchgestrichen. */
/* Betriebsferien: Palme statt durchgestrichener Zahl, die Zahl klein
   darunter. Die Flaeche bleibt ruhig, die Palme traegt die Aussage. */
.np-cal-d--urlaub {
    text-decoration: none;
    flex-direction: column;
    gap: 1px;
    background: color-mix(in srgb, var(--color-accent) 7%, var(--color-neutral-900));
    color: var(--color-neutral-500);
}
.np-cal-d--urlaub .icon { width: 16px; height: 16px; color: var(--color-accent-300); }
.np-cal-d--urlaub small { font-size: var(--text-xs); line-height: 1; }
.np-cal__legend-urlaub .icon { width: 12px; height: 12px; color: var(--color-accent-300); }
.np-dot--urlaub {
    background: repeating-linear-gradient(135deg, var(--color-neutral-600) 0 2px, transparent 2px 4px);
    border: 1px solid var(--color-neutral-600);
}

/* ---------- Newsletter: Band auf der Startseite, schlank im Fuss ----------
   Ein Formular, zwei Auftritte (partials/newsletter-form.php). Das Band
   wirbt, der Fuss bietet nur an - deshalb traegt das Band Ueberschrift,
   Werbetext und Flaeche, und im Fuss bleiben Kicker, Feld und ein
   Kurzhinweis. */

/* Das Band laeuft ueber die volle Breite und liegt in der Farbe der
   Abschnittsbaender, aber ohne deren Cyan: es ist die zweitwichtigste
   Handlung der Seite, nicht die lauteste Flaeche. Gleich darunter steht
   die Abschlusskarte mit der Anfrage - deshalb Band und nicht Karte,
   sonst streiten zwei gleich aussehende Kaesten um dieselbe
   Aufmerksamkeit. */
.np-nlband {
    margin-top: var(--space-16);
    padding: var(--space-12) 0;
    background:
        linear-gradient(120deg,
            var(--color-section) 0%,
            color-mix(in srgb, var(--color-section-glow) 70%, var(--color-bg)) 100%);
    border-block: 1px solid color-mix(in srgb, var(--color-accent) 18%, transparent);
}
.np-nl--band {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 420px);
    align-items: center;
    gap: var(--space-8);
}
.np-nl--band h2 { margin: var(--space-2) 0 0; }
/* Groesse und Farbe kommen aus .np-text, hier steht nur der Abstand. */
.np-nl__intro { margin: var(--space-3) 0 0; }

/* Schmal stehen Text und Feld untereinander. Die Regel steht hier und
   nicht im grossen 820er-Block weiter oben: der kommt in dieser Datei
   VOR den Newsletter-Regeln und verloere gegen sie. */
@media (max-width: 820px) {
    .np-nlband { margin-top: var(--space-10); padding: var(--space-8) 0; }
    .np-nl--band { grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
}

/* Im Fuss: keine Flaeche, kein Rahmen. Die Abgrenzung leistet jetzt das
   Band auf der Startseite - hier wuerde ein Kasten die Spalte erschlagen
   und Marke und Claim an den Rand draengen. */
.np-nl--fuss { margin-top: var(--space-6); max-width: 420px; }
.np-nl--fuss .np-kicker { margin-bottom: var(--space-2); }
.np-nl__row { display: flex; gap: var(--space-2); flex-wrap: wrap; }
.np-nl__row .input { flex: 1 1 180px; min-width: 0; }

/* Der Datenschutzhinweis unter dem Feld: eine Stufe leiser als der Text
   darueber, damit er die Anmeldung nicht erschlaegt - aber nicht so
   leise, dass er als Kleingedrucktes durchgeht. */
.np-nl__hinweis {
    margin: var(--space-3) 0 0;
    font-size: var(--text-sm);
    line-height: 1.5;
    color: var(--color-neutral-400);
}

/* Seite /newsletter (Bestaetigen, Abmelden) */
.np-newsletter { max-width: 640px; }
.np-newsletter .notice { margin: var(--space-4) 0 var(--space-6); }

/* ==================================================================
   Cookie-Hinweis
   ------------------------------------------------------------------
   Eine Karte unten links, kein Vorhang ueber der Seite: die Cookies
   sind alle notwendig, es gibt nichts zu entscheiden, also darf der
   Hinweis das Lesen auch nicht blockieren.

   Er liegt ueber dem Inhalt, aber UNTER der Kopfleiste (z-index 40) - die
   Merkliste und das Burgermenue klappen von dort auf und legen sich ueber
   die ganze Seite. Laege der Hinweis darueber, leuchtete er aus dem
   abgedunkelten Hintergrund heraus.

   Auf schmalen Bildschirmen sitzt er ueber die volle Breite unten -
   dort ist eine Karte "in der Ecke" nur ein Kasten, der Platz kostet.
   ================================================================== */
.np-cookie {
    position: fixed;
    left: var(--space-4);
    bottom: var(--space-4);
    z-index: 35;
    max-width: 480px;
}

.np-cookie__karte {
    padding: var(--space-6);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
    box-shadow: var(--shadow-lg);
}

/* Plaetzchen links, Text rechts. Das Symbol ist gross genug, um als
   Plaetzchen erkannt zu werden - bei Symbolgroesse waere es nur ein
   Kringel mit Punkten. */
.np-cookie__kopf {
    display: flex;
    align-items: center;   /* das Plaetzchen mittig zur ganzen Spalte */
    gap: var(--space-4);
}
.np-cookie__inhalt { min-width: 0; }

.np-cookie__keks {
    width: 56px;
    height: 56px;
    flex: 0 0 auto;
    color: var(--color-accent);
}

.np-cookie__titel {
    margin: 0 0 var(--space-2);
    font-size: var(--text-lg);
    line-height: 1.3;
}

.np-cookie__text {
    margin: 0;
    font-size: var(--text-sm);
    line-height: 1.55;
    color: var(--color-neutral-300);
}

.np-cookie__form { margin-top: var(--space-4); }

.np-cookie__knoepfe {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
}

.np-cookie__link {
    font-size: var(--text-sm);
    color: var(--color-neutral-400);
    text-decoration: underline;
    text-underline-offset: 3px;
}
.np-cookie__link:hover { color: var(--color-text); }

.np-cookie__klein {
    display: block;
    margin: var(--space-3) 0 0;
    font-size: var(--text-sm);
    color: var(--color-neutral-400);
}

/* Die Kategorien - erst sichtbar, wenn es welche zu waehlen gibt
   (ConsentOptionalCategories). Bis dahin rendert das Fragment sie gar
   nicht erst. */
.np-cookie__liste {
    list-style: none;
    margin: 0 0 var(--space-4);
    padding: 0;
    display: grid;
    gap: var(--space-3);
}

.np-cookie__wahl {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    font-size: var(--text-sm);
}
.np-cookie__wahl input { margin-top: var(--space-1); }
.np-cookie__wahl .np-cookie__klein { margin-top: var(--space-05); }

@media (max-width: 620px) {
    .np-cookie {
        left: var(--space-2);
        right: var(--space-2);
        bottom: var(--space-2);
        max-width: none;
    }
    .np-cookie__karte { padding: var(--space-4); }
    .np-cookie__kopf { gap: var(--space-3); }
    .np-cookie__keks { width: 40px; height: 40px; }
}

/* ==================================================================
   Die Karte auf /kontakt

   Ein Rahmen mit fester Form, darin ein Raster aus Kartenkacheln, das
   so verschoben wird, dass der Standort in der Mitte liegt. Die Marke
   sitzt deshalb fest auf 50/50 - sie muss nicht rechnen.

   Die Kachelmasse stehen auch in locationfunctions.php (LOCATION_MAP_*)
   und im Werkzeug werkzeuge/map-tiles.php: fuenf mal drei
   Kacheln zu 256 Pixeln. Wer sie dort aendert, aendert sie hier mit.

   Die Bilder liegen bei uns (html/img/karte/), nicht bei OpenStreetMap -
   beim Aufruf der Seite geht nichts nach aussen.
   ================================================================== */
/* Die Section bringt ihren eigenen Rahmen mit (np-wrap np-sec) - sie
   steht auf der Kontaktseite ausserhalb des zweispaltigen Kastens. */

.np-map__rahmen {
    position: relative;
    overflow: hidden;
    margin-top: var(--space-3);
    /* Breiter als hoch, wie ein Kartenausschnitt sein soll. Die Hoehe
       ist gedeckelt, damit die Karte auf grossen Schirmen nicht die
       halbe Seite einnimmt.

       width: 100% muss dabeistehen. Ohne die Angabe leitet der Browser
       auf breiten Schirmen die BREITE aus der gedeckelten Hoehe ab -
       die Karte wurde dann 960 Pixel schmal und liess rechts daneben
       ein totes Stueck Seite stehen. */
    width: 100%;
    aspect-ratio: 16 / 7;
    max-height: 420px;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    background: var(--color-surface);
}

/* Das Kachelraster. Es ist groesser als der Rahmen und wird so
   geschoben, dass der Punkt (--punkt-links/--punkt-oben, vom Server
   gesetzt) genau in der Mitte landet. */
.np-map__kacheln {
    position: absolute;
    left: calc(50% - var(--punkt-links, 640px));
    top:  calc(50% - var(--punkt-oben, 384px));
    display: grid;
    grid-template-columns: repeat(5, 256px);
    width: 1280px;
    line-height: 0;
}

/* ---------- Die Einfaerbung ----------
   Gilt fuer beide Fassungen: das feste Raster oben und die Kacheln,
   die Leaflet nachlaedt. Eine Regel, damit die Karte beim Umschalten
   nicht die Farbe wechselt. */
.np-map__kacheln,
.np-map__rahmen .leaflet-tile-pane {
    /* OpenStreetMap liefert eine helle Karte. Umgedreht und im Farbkreis
       zurueckgedreht wird daraus eine dunkle, ohne dass sich die Farben
       gegenseitig vertauschen: Gruen bleibt Gruen, nur eben auf Nacht
       statt auf Papier. Etwas entsaettigt und abgedunkelt, damit sie
       neben dem Neongelb der Seite nicht laut wird.

       Ein Filter und keine eigenen Kacheln: die Daten bleiben
       unveraendert, nur ihre Darstellung nicht. */
    filter: invert(1) hue-rotate(180deg) saturate(.55) brightness(.82) contrast(1.05);
}

.np-map__kacheln img { display: block; width: 256px; height: 256px; }

/* Die Marke: ein Ring in Akzentfarbe mit einem Punkt darin. Der
   Schlagschatten hebt sie von der Karte ab - ohne ihn verschwindet sie
   ueber einer hellen Flaeche.

   Zweimal dasselbe Aussehen: __marke sitzt fest in der Mitte des
   festen Rasters, __stift haengt an der beweglichen Karte und wird von
   Leaflet verschoben. Nur das Anheften unterscheidet sich, deshalb
   steht das Aussehen einmal und fuer beide. */
.np-map__marke,
.np-map__stift {
    position: absolute;
    width: 22px;
    height: 22px;
    /* 22 px Inhalt plus zweimal 3 px Rand sind 28 - die halbe Breite
       ist also 14, nicht 11. Mit 11 sass die Marke drei Pixel neben
       dem Haus, was auf einer Karte auffaellt. */
    margin: calc(-1 * var(--space-4)) 0 0 calc(-1 * var(--space-4));
    border: 3px solid var(--color-accent);
    border-radius: 50%;
    background: color-mix(in srgb, var(--color-accent) 25%, transparent);
    box-shadow: 0 0 0 2px var(--color-schatten-mittel), 0 2px 10px var(--color-schatten-tief);
}
.np-map__marke::after,
.np-map__stift::after {
    content: "";
    position: absolute;
    left: 50%;
    top: 50%;
    width: 6px;
    height: 6px;
    margin: calc(-1 * var(--space-1)) 0 0 calc(-1 * var(--space-1));
    border-radius: 50%;
    background: var(--color-accent);
}

/* Das feste Raster ist so geschoben, dass der Standort in der Mitte
   des Rahmens liegt - die Marke muss deshalb nicht rechnen. */
.np-map__marke { left: 50%; top: 50%; }

/* Auf der beweglichen Karte setzt Leaflet den Anker auf den Punkt;
   Stift und Blase haengen mit left/top 0 daran. */
.np-map__stift { left: 0; top: 0; }

.np-map__quelle {
    margin-top: var(--space-2);
    font-size: var(--text-sm);
    color: var(--color-neutral-400);
}

.np-map__wege {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-3);
}

@media (max-width: 700px) {
    /* Am Telefon hoeher als breit waere verschwendet - der Ausschnitt
       wird quadratischer, damit links und rechts noch Strassen zu sehen
       sind. */
    .np-map__rahmen { aspect-ratio: 4 / 3; max-height: 320px; }
}

/* ---------- Die Sprechblase an der Marke ----------
   Sie sitzt ueber dem Punkt und nennt Namen und Anschrift. Eine Karte
   ohne Beschriftung laesst raten, welches der Haeuser gemeint ist.

   Die Blase haengt an derselben Mitte wie die Marke; translate schiebt
   sie um ihre halbe Breite nach links und ganz nach oben, sodass ihre
   Spitze auf dem Punkt sitzt. So braucht sie keine eigenen Masse. */
.np-map__blase {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, calc(-100% - 20px));
    z-index: 2;
    margin: 0;
    padding: var(--space-3) var(--space-4);
    max-width: min(300px, calc(100% - 32px));
    border-radius: var(--radius-md);
    background: var(--color-surface);
    box-shadow: 0 0 0 1px var(--color-divider), 0 10px 24px -10px var(--color-schatten-blase);
    text-align: center;
    line-height: 1.35;
}
.np-map__blase strong { display: block; font-size: var(--text-base); }
.np-map__blase span   { display: block; font-size: var(--text-sm); color: var(--color-neutral-300); }

/* Die Spitze: ein gedrehtes Quadrat unter der Blase, in derselben Farbe
   wie sie. Der Rand wird nur an zwei Seiten gezeichnet, damit die Kante
   der Blase darueber nicht durchscheint. */
.np-map__blase::after {
    content: "";
    position: absolute;
    left: 50%;
    bottom: -6px;
    width: 12px;
    height: 12px;
    margin-left: calc(-1 * var(--space-2));
    transform: rotate(45deg);
    background: var(--color-surface);
    border-right: 1px solid var(--color-divider);
    border-bottom: 1px solid var(--color-divider);
}

@media (max-width: 700px) {
    /* Am Telefon ist der Rahmen niedrig - die Blase rueckt naeher an
       die Marke, damit sie nicht oben herausragt. */
    .np-map__blase {
        transform: translate(-50%, calc(-100% - 16px));
        padding: var(--space-2) var(--space-3);
    }
    .np-map__blase strong { font-size: var(--text-sm); }
    .np-map__blase span   { font-size: var(--text-xs); }
}

/* ==================================================================
   DIE BEWEGLICHE KARTE (Leaflet)
   ------------------------------------------------------------------
   Ist JavaScript da, raeumt main.js das feste Raster weg und laesst
   Leaflet den Rahmen uebernehmen. Die Bilder bleiben dieselben - nur
   holt Leaflet sie jetzt stufenweise und nachladend.

   Leaflet bringt ein eigenes Stylesheet mit (css/leaflet.css), das nur
   auf der Kontaktseite geladen wird. Es ist auf helle Karten mit
   weissen Bedienelementen ausgelegt; was hier steht, holt es auf die
   dunkle Seite herueber. Mehr nicht - die Mechanik bleibt seine.
   ================================================================== */

/* Leaflet setzt der Flaeche eine eigene Schrift und einen grauen
   Untergrund. Beides ueberschreiben, sonst blitzt zwischen den
   Kacheln Hellgrau durch. */
.np-map__rahmen.leaflet-container {
    font: inherit;
    background: var(--color-surface);
}

/* Der Anker der Marke: ein Punkt ohne Ausdehnung, den Leaflet auf die
   Koordinate schiebt. Stift und Blase haengen mit left/top 0 daran.
   Ohne pointer-events: none faengt er Zieh-Gesten ab, die der Karte
   gehoeren. */
.np-map__anker {
    width: 0;
    height: 0;
    pointer-events: none;
}

/* Die Sprechblase auf der beweglichen Karte. Sie sieht aus wie die im
   festen Raster; nur das Anheften ist anders, weil unter ihr nicht der
   Rahmen sitzt, sondern der Anker auf der Koordinate.

   Die Verschiebung (halbe Breite nach links, ganz nach oben plus 20
   Pixel) steht schon in .np-map__blase und passt hier unveraendert. */
.np-map__blase--live {
    left: 0;
    top: 0;
    /* Ihr Kasten hat keine Breite, an der sich Prozente messen
       koennten - deshalb hier eine feste Obergrenze statt der
       Prozentrechnung der festen Fassung. */
    width: max-content;
    max-width: min(300px, 72vw);
}

/* ---------- Die beiden Zoomknoepfe ----------
   Leaflet liefert sie als weisse Kaesten mit grauem Rand. Hier stehen
   sie auf demselben dunklen Grund wie alles andere. */
.np-map__rahmen .leaflet-bar {
    border: 0;
    border-radius: var(--radius-sm);
    box-shadow: 0 2px 10px var(--color-abdunkeln);
}
.np-map__rahmen .leaflet-bar a,
.np-map__rahmen .leaflet-bar a:hover {
    width: 32px;
    height: 32px;
    line-height: 32px;
    border-bottom-color: var(--color-divider);
    background: var(--color-surface);
    color: var(--color-neutral-100);
    font-weight: 700;
}
.np-map__rahmen .leaflet-bar a:hover,
.np-map__rahmen .leaflet-bar a:focus-visible {
    background: color-mix(in srgb, var(--color-text) 8%, var(--color-surface));
    color: var(--color-accent);
}
.np-map__rahmen .leaflet-bar a.leaflet-disabled {
    background: var(--color-surface);
    color: var(--color-neutral-500);
}

/* ---------- Der Hinweis ----------
   Er erscheint, wenn jemand ueber der Karte scrollt, ohne sie vorher
   angeklickt zu haben - und am Telefon beim ersten Finger. Ungefragt
   das Mausrad abzufangen macht die Seite unbedienbar: man kommt an
   der Karte nicht mehr vorbei. Also erst sagen, was zu tun ist.

   Er liegt ueber allem, faengt aber nichts ab (pointer-events: none) -
   sonst waere gerade der Klick blockiert, um den er bittet. */
.np-map__hinweis {
    position: absolute;
    inset: 0;
    z-index: 1100;   /* ueber Leaflets Bedienelementen (1000) */
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    background: var(--color-karte-hinweis);
    color: var(--color-text);
    font-size: var(--text-base);
    font-weight: 600;
    text-align: center;
    opacity: 0;
    visibility: hidden;
    transition: opacity .2s ease, visibility .2s ease;
    pointer-events: none;
}
.np-map__hinweis.an {
    opacity: 1;
    visibility: visible;
}

@media (prefers-reduced-motion: reduce) {
    .np-map__hinweis { transition: none; }
}
