@charset "utf-8";

/* ===========================================================================
   INTER - the brand typeface, self-hosted
   ===========================================================================

   Two files, latin subset only. The latin range covers all six languages:
   German ä ö ü ß, French é è à ç, Italian, Spanish ñ á and Dutch all live in
   U+0000-00FF, plus Œ œ at U+0152-0153. latin-ext would add the ĳ ligature
   and nothing else anyone types here.

   Variable on the `wght` axis alone, 100 to 900 in one file. That range is
   the point: the system font reliably offers 400 and 700, Inter offers
   everything between - and weight is the contrast this design was missing.

   Italic is loaded, not synthesised. `item.js richtext` turns `*kursiv*` into
   an `<em>`, so editorial text really is italic; a browser-slanted Inter
   looks wrong.

   Served from `web/fonts/`. `scripts/assets.ts` copies everything under
   `web/` into `dist` after the Astro build, `font-src 'self'` is already in
   both CSP files and `.woff2` is already in the preview's type table - no
   plumbing needed for either.
   =========================================================================== */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/inter-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+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: italic;
  font-weight: 100 900;
  font-display: swap;
  src: url("/fonts/inter-latin-italic.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+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* **The hand on the polaroid** - Caveat, the one face that is not the house
   face: the name on a polaroid is written, not set. Chosen for its ampersand,
   which many names carry ("Restaurant & Bar"). Latin subset (all umlauts and
   French accents are in it), cut to the one weight in use (400), 48 kB,
   self-hosted like Inter. No
   preload and no fallback metrics: it sits at the end of the page, in a box
   of fixed height, so the swap changes shapes and never the layout. */
@font-face {
  font-family: "Caveat";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/caveat-latin-400.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+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/**
 * **The fallback that holds the line until Inter arrives.**
 *
 * The acceptance run measures CLS and it stands at 0. `font-display: swap`
 * alone would break that: the fallback sets the text, Inter replaces it, and
 * every line reflows. These four overrides make the fallback occupy the space
 * Inter will need, so the swap changes the shapes and not the layout.
 *
 * **The numbers are measured, not guessed.** Five representative strings - a
 * name, a place with umlauts, a full sentence, the alphabet with ä ö ü ß -
 * summed through each font's own advance widths: Inter runs **5.8 % wider
 * than Arial** and **12.0 % wider than SF Pro**. `size-adjust` closes that
 * gap; the ascent and descent overrides then restore Inter's own vertical
 * metrics (1984 / -494 on a 2048 em) on top of the adjusted size.
 *
 * **Arial is the anchor because its metrics are identical on macOS and
 * Windows.** SF Pro would fit a Mac better, but one face cannot serve three
 * platforms - and being 6 % off everywhere beats being right on one and 12 %
 * off on the next. Recompute all four whenever the font file changes.
 */
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  size-adjust: 105.78%;
  ascent-override: 91.58%;
  descent-override: 22.80%;
  line-gap-override: 0%;
}

/* Farben aus dem Styleguide, Kapitel 3 - nicht erfunden.
   Weiß ist der Hintergrund, Body die Fließtextfarbe, Schwarz sind Überschriften
   und primäre Elemente. Die fünf Kategoriefarben sind fest mit ihren Bereichen
   verknüpft und stehen deshalb NICHT als allgemeine Akzentfarbe zur Verfügung -
   die Rolle hat Schwarz.

   ===========================================================================
   HELL UND DUNKEL - die Regel für alles, was hier dazukommt
   ===========================================================================

   **Jede Farbe steht als Wert hier oben, nicht im Bauteil.** Wer irgendwo im
   Stylesheet ein `#ffffff` oder ein `rgba(0,0,0,.06)` schreibt, baut eine Farbe,
   die den Dunkelmodus nicht kennt - und der Fehler zeigt sich erst Wochen
   später bei jemandem, dessen Gerät dunkel steht.

   Drei Zustände, und alle drei müssen bedient werden:

     1. `:root`                       hell - die vollständige Palette
     2. `prefers-color-scheme: dark`  die Voreinstellung des Geräts,
                                      abgesichert gegen eine ausdrückliche
                                      Wahl "hell"
     3. `[data-theme="dark|light"]`   die ausdrückliche Wahl des Gastes,
                                      sie gewinnt in beide Richtungen

   **Der Navigationsblock ist immer das Gegenteil der Seite.** Deshalb wird er
   nicht je Modus gesetzt, sondern abgeleitet: `--nav` ist `--strong`, `--nav-ink`
   ist `--paper`. Hell heißt schwarzer Block mit weißer Schrift, dunkel heißt
   weißer Block mit dunkler Schrift - eine Regel, zwei Modi, kein zweiter Ort,
   an dem sie auseinanderlaufen kann.

   **Eine Ausnahme, mit Grund:** Der Bildnachweis auf dem Foto (`.credit-chip`)
   trägt feste Farben. Er liegt auf einem Bild und muss dort in beiden Modi
   lesbar bleiben - ein Nachweis, der im Dunkelmodus dunkel wird, verschwindet
   auf einem nächtlichen Foto.
   =========================================================================== */
:root {
  /* Hell und dunkel werden beide unterstützt - das sagt dem Browser, dass er
     Formularelemente und Bildlaufleisten mitziehen darf. */
  /* Solange nur hell ausgeliefert wird, soll der Browser Formularelemente und
     Bildlaufleisten auch hell zeichnen. */
  color-scheme: light;

  /**
   * **Der Einzug - eine Zahl, drei Leser.**
   *
   * Er ist der Rand der Seite (`main`), der Innenabstand des Namensetiketts
   * auf einer Kachel und der Einzug ihrer Fusszeile darunter: Titel und Text
   * stehen damit auf derselben Kante. Und `--rahmen` rechnet ihn ab
   * (`min(100vw, --rahmen-breite) - 2 * --inset`) - die zwei Bloecke, die
   * ueber die Lesespalte hinausgreifen, muessen den Rand kennen, gegen den sie
   * stossen. **Deshalb steht er hier und nicht als Zahl an `main`:** Zwei
   * Werte, die uebereinstimmen muessen, sind einer zu viel.
   */
  --inset: 1rem;

  /* Der schraege Pfeil fuer Verweise nach draussen. Dieselben zwei Pfade wie
     `ROW_ICON.outside` in `chrome.js` - ein Zeichen, zwei Ausgabewege. */
  --icon-external: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 7h10v10"/><path d="M7 17 17 7"/></svg>');

  /**
   * **Der gerade Pfeil - Lucide `arrow-right` (ISC), Strich und Spitze.**
   *
   * Genau die Form, die in der Galerie weiterblaettert (`backIcon()` /
   * `forwardIcon()` in `item.js`): derselbe Pfad, dieselbe Strichstaerke. Sie
   * ist damit **das** Zeichen fuer "einen Schritt weiter" im Guide - und weil
   * gedreht wird und nicht neu gezeichnet, ist "weiter" und "hier geht etwas
   * auf" dieselbe Form in zwei Lagen.
   *
   * Als Token, weil ihn inzwischen drei Stellen brauchen (Textverweis,
   * Abschnittsverzeichnis, und die naechste kommt). Vorher stand der Pfad
   * zweimal ausgeschrieben im Stylesheet - zwei Stellen, an denen eine
   * Strichstaerke auseinandergehen kann.
   */
  --icon-arrow: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>');

  /**
   * **The two families, as tokens.**
   *
   * `--font` names Inter first, the metric-matched fallback second and the
   * device font last - three steps, each one a little further from the brand
   * and each one still the right shape.
   *
   * `--mono` used to stand written out **four times** in this file, and in
   * two different spellings (one of them carried `Consolas`, three did not).
   * That is "one thing, one place" arguing with itself. One token, five
   * readers, and the next surface that needs it does not invent a fifth
   * spelling.
   */
  --font: "Inter", "Inter Fallback", -apple-system, BlinkMacSystemFont,
    "Segoe UI", system-ui, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /**
   * **Die Groesse einer Abschnittsueberschrift** - als Token, weil sie an
   * mehreren Flaechen gilt und weil eine Zahl, die an zwei Stellen steht, an
   * einer davon irgendwann eine andere ist. Wer eine Ueberschrift kleiner
   * braucht (Trefferliste, Farbkasten im Styleguide), setzt dort ihren eigenen
   * Wert - der Rest liest diesen hier.
   */
  --fs-h2: 1.725rem;

  /**
   * **Der Grund, die Flaeche, die weiche Ecke und der Schatten der
   * Statistikkacheln** - nur im Backend. Als Token, weil ein `rgba()` im
   * Bauteil im Dunkelmodus in die falsche Richtung zeigt und weil mehrere
   * Flaechen sie teilen (die Karte, die Kachel darin und das Kurvenquadrat in
   * der Tabelle).
   *
   * **Die Kachel hat keinen Rahmen - ihre Grenze ist der Helligkeitsschritt.**
   * Ein Strich **und** ein Schatten sind zwei Antworten auf dieselbe Frage,
   * und der Strich gewinnt sie immer: Man sieht dann einen Kasten mit
   * Schlagschatten statt einer Flaeche, die liegt. Damit das traegt, muss der
   * Grund darunter ein anderer sein als die Kachel - deshalb sind es **zwei**
   * Token und nicht `--paper` fuer beides. Die Kachel ist in beiden Modi die
   * **hellere** Flaeche; das ist die Aussage „liegt oben", und sie kehrt sich
   * im Dunkeln nicht um.
   *
   * **Der Schatten faellt nach unten und tritt oben nicht aus.** Beide Lagen
   * tragen einen negativen Spread, der groesser ist, als der Weichzeichner
   * ueber die Oberkante hinausreicht - `0 8px 18px -6px` beginnt 14 px unter
   * der Kante und blendet 9 px auf, steht also 5 px **darunter**; zur Seite
   * sind es 3 px, nach unten 11. Ein Schatten, der oben genauso liegt wie
   * unten, ist ein Rand mit weicher Farbe; einer, der nur faellt, ist Licht
   * von vorn oben. Zwei Lagen: eine enge, die die Kachel absetzt, und eine
   * weite, die sie traegt. Eine einzelne Lage sieht entweder gedruckt oder
   * schwebend aus.
   */
  --backend-ground: #f8f9fa;
  --card-ground: #ffffff;
  --card-radius: .5rem;
  --card-shadow: 0 1px 2px -1px rgba(16, 24, 32, .10), 0 8px 18px -6px rgba(16, 24, 32, .18);

  --paper: #ffffff;   /* Weiß - Hintergründe */
  --ink: #2e363c;     /* Body - Fließtext */
  --strong: #000000;  /* Schwarz - Überschriften, primäre Elemente */
  --soft: #6c757d;    /* Gray 600 - Sekundärtext */
  --line: #e9ecef;    /* Gray 200 - Trennlinien */
  --accent: #000000;  /* primäre Elemente, siehe oben */
  /* Ein leiser Grund für Flächen, die auf der Seite liegen (Kartenrahmen,
     leere Kacheln). Als Token, weil ein rgba() im Bauteil im Dunkelmodus in die
     falsche Richtung zeigt. */
  --shade: #f2f4f6;
  /* **Der Grund hinter einem ladenden Video** - dunkel in **beiden** Modi, und
     deshalb ein eigenes Token. Vorher stand dort `--strong`, und das ist im
     Dunkelmodus Weiß: Zwischen zwei Absätzen blitzte ein weißes 16:9-Rechteck
     auf, bis der Player kam. Ein Videorahmen ist schwarz, weil ein Bild darin
     anläuft - das ist keine Aussage über hell und dunkel. */
  --videogrund: #12161a;
  /* **The bar of the guest folder is black in both modes** - it is the roof of
     an app on the house's phone, not a surface of the page, and a white bar
     in the dark read as a different app. Its own token, like the video
     ground: `--nav` turns light in the dark, this does not. */
  --mappe-kopf: #000000;
  /* **The newsletter box on the merchandise page is black in both modes** -
     it stands among product photos, where the blue of Entdecken would claim
     a section the page does not belong to. Not `--strong`, which turns white
     in the dark. */
  --merch-post-ground: #000000;
  /* **The credit on a photo keeps its colours in both modes** - a light chip
     with dark ink. It lies on a picture, not on the page: `--strong` and
     `--ink` turn light in the dark, and the i and the credit vanished on the
     white chip. Same values in the dark block, stated there on purpose. */
  --credit-grund: rgba(255, 255, 255, .92);
  --credit-ink: #000000;
  /* **The polaroid** - its frame is white because it pictures a photo you hold
     in your hand; in the dark it is a broken white, since five pure white
     squares on a dark page glare. The shadow is the documented exception to
     "cards carry no shadow" (the reason of the voucher: a thing, not a box of
     the layout) and falls away in the dark, where it would not show. The tape
     is not a token: four hand-drawn images (`web/polaroid-streifen-<n>.webp`,
     source `assets/images/polaroid-streifen/`), the same in light and dark,
     like real tape. */
  --polaroid-rahmen: #ffffff;
  --polaroid-schatten: 0 1px 1px rgba(16, 24, 32, .10), 0 4px 8px -2px rgba(16, 24, 32, .12),
    0 18px 32px -12px rgba(16, 24, 32, .30);
  /* Measured on the model print: the frame runs from white at the top to a
     light grey at the bottom, the right side lies a little in the shade, a
     soft band crosses the lower margin, and a hair of an edge runs round. */
  --polaroid-rahmen-unten: #f3f3f0;
  --polaroid-seite: rgba(0, 0, 0, .035);
  --polaroid-band: rgba(0, 0, 0, .03);
  --polaroid-kante: rgba(0, 0, 0, .10);
  /* The photo sits recessed: a fine shade at its upper edge, a line round it,
     and a faint sheen from the upper left. */
  --polaroid-bild-schatten: inset 0 1px 3px rgba(0, 0, 0, .45), inset 0 0 0 1px rgba(0, 0, 0, .14);
  --polaroid-glanz: rgba(255, 255, 255, .16);
  /* The ink of a blue ballpoint, taken from the template
     (`manuel-polaroid-960.webp`). Not a rubric colour and not a state: it is
     the pen, and it stays the same in dark mode because the frame stays
     light (8.6 : 1 on the lower frame, 7.4 : 1 on its dark-mode grey). */
  --polaroid-tinte: #2b3c9b;

  /**
   * **Die Zustandsfarben - guide-eigen, nicht aus der Marke.**
   *
   * Die Marke hat keine Signalfarben: Ihre fuenf Farben sind fest mit den
   * Kategorien verknuepft (`assets/colors/README.md`) und duerfen nichts
   * anderes bedeuten - Weinrot heisst "Unterkuenfte" und nicht "abgelehnt".
   * Diese drei Paare gelten deshalb nur fuer Zustandsmarken und sind
   * absichtlich gedaempft: Sie sollen neben Forest und Weinrot nicht schreien.
   *
   * Als Token und nicht im Bauteil, weil sie im Dunkelmodus anders lauten -
   * ein aufgehellter Grund wird dort dunkel und die Schrift hell.
   */
  /**
   * **Der Pfeil der Auswahlfelder** - als Token, weil eine Datenadresse keine
   * `currentColor` kennt: Im Dunkeln muss ein zweiter Pfeil her, und beide
   * stehen deshalb dort, wo auch die Farben stehen.
   */
  --chevron: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17' fill='none' stroke='%23000000' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><path d='M4.6 6.8 8.5 10.6 12.4 6.8'/></svg>");
  /**
   * **Wie gross der Pfeil steht** - eine Zahl, zwei Leser: das Auswahlfeld
   * (`select`) und der Aufklapper mit Haken (`.mehrwahl`). Getrennt getippt
   * waeren es zwei Pfeile, die man nebeneinander sieht und einzeln nachzieht.
   * Er steht auf einer Zeile von 1 rem, ist also so hoch wie ein Buchstabe -
   * kleiner las er sich neben der Schrift als Staubkorn.
   */
  --chevron-groesse: 1rem;
  /**
   * **Die Ecke der Bedienteile** - Eingabefeld, Auswahl, Textkasten, Knopf.
   *
   * Die Marke sagt `border-radius: 0`, und fuer Flaechen gilt das weiter:
   * Kachel, Kasten, Schicht, Bild. **Was man anfasst, traegt 4 px** - dieselbe
   * Zahl, die das Zeichen beim Zeigen schon hatte. Eine Zahl an einer Stelle:
   * Wer sie aendert, aendert sie fuer alle vier Sorten auf einmal.
   */
  --feld-radius: 4px;
  /**
   * **Die Hoehe der Bedienteile** - dieselbe Zahl fuer Feld, Auswahl,
   * Aufklapper und Knopf.
   *
   * Sie stand nur an den Formularfeldern; der Knopf rechnete seine Hoehe aus
   * Polster und Schriftgroesse (42,4 px), der Aufklapper legte seinen Rahmen
   * oben drauf (46,8 px), das Feld daneben mass 44,8. Drei Bauteile in einer
   * Reihe, drei Hoehen - und weil sie unten ausgerichtet stehen, sieht man es
   * an drei Oberkanten. Eine Zahl, vier Leser.
   */
  --feld-hoehe: 2.8rem;
  --state-wait-bg: #f4eedd;  /* wartet auf Pruefung */
  --state-wait-ink: #5b4712;
  --state-live-bg: #e3ece3;  /* steht oeffentlich */
  --state-live-ink: #22421e;
  --state-stop-bg: #f0e4e6;  /* nicht freigegeben */
  --state-stop-ink: #5e1c24;
  /* The dot on the bell: something unread. A signal, not a state of an item -
     so none of the state pairs, and no rubric colour. */
  --glocke-punkt: #d93a2b;
  /**
   * **The colour of a curve** - one token, every chart in the backend.
   *
   * A curve is a **figure**, not a state: `--state-live-*` means "published"
   * everywhere in the backend - the mark on a row, the toggle for the front
   * page, the filled month in the year band. Borrowing it for a line would
   * give one token two jobs, and the next screen puts them side by side.
   *
   * It is guide-owned, like the state colours, and for the same reason: the six
   * brand colours are bound to the categories (`assets/colors/README.md`) and
   * must not mean anything else - Forest is "Orte", not "views".
   *
   * **Two values, both read like text.** 6.4 : 1 on white here, 5.1 : 1 on the
   * dark ground below - a one-pixel line needs the contrast of a letter, not
   * of a surface. The area under the line is this colour at 22 %, so it is one
   * value and not a second one to keep in step.
   *
   * **The rule the token cannot enforce:** no curve into a table that carries
   * the front-page toggle, no state mark into a card that carries a curve.
   * Today no screen has both, and as colours the two greens are 1.75 : 1 apart
   * - which is to say: the same green. What keeps them apart is this sentence,
   * not the fact that they have separate names.
   */
  --chart: #2c6b38;
  /**
   * Die Breite der **Lesespalte** - schmaler als der Inhaltsrahmen (1100).
   *
   * Bilder, Karten und Kacheln nutzen die ganze Breite; Text nicht. Eine Zeile
   * von 1100 Pixeln hat gut 130 Zeichen, und beim Zeilenwechsel findet das Auge
   * den Anfang nicht wieder. **52 rem** sind etwa 85 Zeichen - noch im Bereich,
   * in dem man ohne Kopfbewegung liest, und auf einem breiten Schirm steht der
   * Text damit weniger schmal unter einem 1060 px breiten Bild.
   */
  --text: 52rem;

  /**
   * **Der Rahmen - ein Mass, als Token.** 68,75 rem sind 1100 px bei der
   * Grundschrift von 16 px. Sieben Stellen deckeln damit (`main`, Kopf, Fuss,
   * Buehne, `--rahmen` an Merchandise und Wetter); in Pixeln
   * geschrieben stuende die Zahl siebenmal und bliebe beim Vergroessern stehen.
   *
   * **Die Wurzel steht an jeder Breite bei 16 px** - der Guide skaliert nicht
   * nach der Fensterbreite. Groesser liest, wer im Fuss die Schriftgroesse
   * hochstellt (`data-text-size`) oder im Browser zoomt; weil alles in rem
   * steht, waechst dann Rahmen, Schrift und Abstand in einem Verhaeltnis.
   */
  --rahmen-breite: 68.75rem;

  /**
   * **The category colours** - from the brand palette
   * (`assets/colors/README.md`, `assets/colors/brand-colors.css`), one list
   * for magazine and guide.
   *
   *   Uebernachten  #8a1a2e  sour cherry - the cherry on the Black Forest cake
   *   Geniessen     #c99a55  gold
   *   Entdecken     #1f4e78  blue
   *   Erleben       #1e4a36  silver fir
   *   Orte          #6a6258  granite
   *   Menschen      #4a2b1c  dark chocolate - magazine only
   *
   * **Muted, but never black.** The rule behind the values: every colour
   * stays at least dE 23 away from the body text (`--ink`), because a mark
   * of 14 to 21 px is a thin stroke, and a dark blue next to black text reads
   * as black. Cherry and chocolate sit 30 degrees of hue apart, so people is
   * a brown and not a darker stay. Closest pair within the six: dE 25.4
   * (places / people); within the four guide categories: dE 41.4.
   *
   * White on the surface measures 6.0 to 12.7 : 1 - gold excepted, see below.
   */
  --rubrik-stay: #8a1a2e;
  --rubrik-eat: #c99a55;
  --rubrik-discover: #1f4e78;
  --rubrik-experience: #1e4a36;
  --rubrik-places: #6a6258;
  --rubrik-people: #4a2b1c;
  /**
   * **One colour, two lightnesses - and only gold needs the second.**
   *
   * `--rubrik-eat` is the surface colour: the white drawing of the mark sits
   * on it. As **ink on paper** it measures 2.55 : 1 against white and fails
   * both thresholds - 3 : 1 for a graphic, 4.5 : 1 for text.
   *
   * `#87602a` is the same hue (36 vs. 35 degrees, saturation 0.52 vs. 0.53);
   * only the lightness drops from 0.56 to 0.35. That gives **5.62 : 1**. Same
   * construction as the state pairs of the house, for the same reason: what
   * sits on a surface and what sits on paper are two jobs for one colour.
   *
   * Read through a fallback (`var(--rubrik-eat-ink, var(--rubrik-eat))`, as
   * `--rf-voll` does): whoever adds a mark has nothing to do;
   * whoever picks a light colour adds an ink.
   */
  --rubrik-eat-ink: #87602a;
  /**
   * **Die Hoehe eines Reglers - 2,25 rem (36 px), ueberall.**
   *
   * Der Umschalter „Liste / Karte" und die Rubrikfelder daneben sind das, was
   * auf dem Telefon mit dem Daumen getroffen wird. 36 px ist die Hoehe, bei der
   * vier Kreise **und** der Umschalter auf 375 px noch in **eine** Zeile
   * passen - bei 40 taten sie es nicht, und die Reihe brach um. Sie steht als
   * Zahl an **einer** Stelle, weil zwei Bauteile sie teilen und in einer Reihe
   * nebeneinander stehen: Zwei Werte waeren zwei Hoehen in einer Zeile, und
   * das sieht man sofort.
   *
   * **In rem, nicht in px:** Der Umschalter traegt Schrift und waechst mit
   * einer groesseren Browserschrift ueber seine Mindesthoehe hinaus; Kreise in
   * px blieben dann kleiner als er. In rem wachsen alle Regler gemeinsam.
   */
  --regler-hoehe: 2.25rem;
  /**
   * **Die Miniatur vor einer Zeile - ein Mass fuer alles.**
   *
   * Ein Eintrag stand in der Gaestemappe auf 64 px, eine Veranstaltung ueberall
   * auf 44 - dieselbe Sorte Zeile mit zwei Bildgroessen, und im selben Fenster
   * untereinander sah man es sofort. **60 px** ist die eine Zahl: Bei 44
   * verschwindet ein Primärbild, bei 64 draengt es den Namen.
   *
   * Gelesen von der Terminzeile, der Liste der Mappe und den Nachbarorten -
   * und von den `width`/`height` am `img`, damit der Platz vor dem Laden
   * freigehalten wird. Stimmt die Zahl dort nicht mit dieser ueberein, springt
   * die Zeile beim Laden.
   *
   * **Und sie tragen eine kleine Rundung** (`--thumb-radius`, 4 px) - dasselbe
   * Mass wie das Primärbild in der Trefferliste und der Platzhalter der
   * Terminzeile. Eckig neben den runden Bedienteilen wirkte die Zeile haerter,
   * als sie ist; rund waere es ein Portraet, und das ist es nicht.
   */
  --thumb: 60px;
  /**
   * **The search layer has its own, smaller square: 44 px** - the size of the
   * picture in the backend tables. A suggestion is two short lines, name and
   * place, together about 44 px high; a 60 px picture made the row taller than
   * its text and put fewer results on a phone screen. The 60 above holds where
   * the picture carries the information - calendar, "Was ansteht", folder,
   * neighbouring places. No event row stands in the search, so the two sizes
   * never stand one under the other.
   */
  --such-thumb: 44px;
  --thumb-radius: 4px;
  /* The gap between the quiet line and the name in a list row - event row,
     folder list. One number, so the two lists breathe alike. */
  --zeile-abstand: .3rem;
  /* Abgeleitet: der Block ist das Gegenteil der Seite. */
  --nav: var(--strong);
  --nav-ink: var(--paper);
  /**
   * **Text on the picture has its own token.** `--nav-ink` is derived and
   * turns dark in the dark theme - on a photograph that is dark text on a
   * dark picture. A photo has no light and dark: the ink on the stage is
   * white, in both themes.
   */
  --auf-bild-ink: #ffffff;
}

/**
 * ===========================================================================
 * **DAS ZWEITE RAHMENMASS - ab 84 rem, und es gibt genau einen Grund dafuer**
 * ===========================================================================
 *
 * Ab 1344 px steht die **dritte Kachel** je Reihe, und der Rahmen waechst
 * dafuer von 1100 auf 1280 px. Am 1100er Rahmen waere die dritte Kachel
 * 332 px breit und ihr Foto darin 302 - schmaler als das **Nebenbild** einer
 * Eintragsseite (`SIZES.galerie`, 350). Ein Aufmacher in einer Liste darf nicht
 * kleiner sein als ein Beiwerk auf der Detailseite.
 *
 * **1280 und nicht mehr**, gerechnet an `BILD_BREITEN` (370 · 740 · 1110 ·
 * 1480): Bei 1280 misst das Foto im Abzug 357 px und holt die 370er Fassung,
 * auf einem feinen Schirm die 740er. Bei 1324 misst es 370,1 - eine
 * Zehntelpixel ueber der Stufe, und der Browser holt 740 bzw. 1110. **Das
 * doppelte Gewicht fuer vier Prozent mehr Bild.** Die Zahl ist damit nicht
 * gegriffen, sondern die letzte, die in die guenstige Stufe faellt.
 *
 * **Eine Zahl schaltet beides** - Rahmen und Spaltenzahl (siehe das
 * Kachelraster weiter unten). Zwei Zahlen waeren eine Breite, an der drei
 * Kacheln in einem 1100er Rahmen stehen, und genau die ist zu schmal.
 *
 * **Und der Punkt liegt ueber dem Mass, nicht darauf.** Schaltete er bei
 * 80 rem, waere die Seite bei genau 1280 px randlos: Rahmen gleich Fenster,
 * Ueberschrift und Fuss klebten an beiden Kanten. Bei 84 rem bleiben im
 * schmalsten Fall 32 px Luft je Seite, und von dort waechst sie mit dem
 * Fenster.
 *
 * **Eine Kante, nicht zwei:** Kopf, Fuss, Buehne, `main` und die zwei
 * `--rahmen`-Rechnungen lesen alle dieses eine Token und wandern mit. Nur das
 * Raster zu verbreitern hiesse, dass Ueberschrift, Zaehlzeile, Suchzeile und
 * Reiter 58 px innerhalb der Kachelkante stuenden - und auf der Ergebnisseite
 * waere die Karte, die derselbe Reiter zeigt, schmaler als die Liste.
 *
 * **Der Preis, offen:** Das Kopfbild einer Eintragsseite waechst von 1068 auf
 * 1440 px, und die groesste Fassung bleibt 1480 - viel Luft nach oben bleibt
 * da nicht. Vier `sizes`-Angaben ziehen mit (`SIZES` in `web/item.js`), sonst
 * holt der Browser zu klein und niemand sieht warum.
 *
 * **Und der Rahmen ist breiter als sein eigener Schaltpunkt.** Zwischen 84 rem
 * (1344 px) und 92 rem (1472 px) deckelt nicht mehr der Rahmen, sondern das
 * **Fenster**: Dort steht der Inhalt randlos bis auf die zwei `--inset`. Wer
 * die Seite auf einem 1366er Schirm ansieht, sieht sie also ohne den Rand, den
 * sie darunter und darueber hat. Deshalb tragen drei `sizes`-Angaben fuer
 * dieses Band eine eigene Stufe mit `calc(100vw - …)` - eine feste Zahl waere
 * dort entweder zu gross oder zu klein.
 */
@media (min-width: 84rem) {
  :root { --rahmen-breite: 92rem; }
}

/* ===========================================================================
   DUNKEL IST VORBEREITET, ABER NICHT AKTIV
   ===========================================================================

   Entschieden am 03.09.2026: Der Umschalter ist wieder draußen, und die
   automatische Umschaltung nach Geräteeinstellung bleibt **abgeschaltet**.

   Nicht weil sie nichts wert wäre - Fotos wirken auf dunklem Grund besser -,
   sondern weil eine zweite Erscheinung zweimal geprüft werden muss: Karte,
   Bildnachweis, Schräge, Fuß. Ein dunkles Aussehen, das niemand angesehen hat,
   ist schlechter als ein helles, das stimmt. Der Styleguide sagt bisher
   dasselbe: „Kein Dunkelmodus - die Seite steht auf Weiß."

   **Was bleibt:** die Palette und die Regel, dass jede Farbe ein Token ist. Das
   Anschalten ist damit ein Handgriff an genau einer Stelle - `light dark` in
   `color-scheme`, und den Block unten von `[data-theme="dark"]` auf
   `@media (prefers-color-scheme: dark)` umstellen. Wer neue Bauteile baut, hält
   sich weiter an die Token: Sonst ist der Handgriff später eine Suche.
   =========================================================================== */
:root[data-theme="dark"] {
  --paper: #12161a;
  --ink: #dfe4e7;
  --strong: #ffffff;
  --soft: #98a1a8;
  /* Im Dunkeln traegt ein Schatten kaum - er wird deshalb tiefer. Die Grenze
     der Kachel macht hier ohnehin der Helligkeitsschritt: Der Grund bleibt
     der dunkelste Wert, die Kachel steht eine Stufe darueber. */
  --backend-ground: #12161a;
  --card-ground: #1b2126;
  --card-shadow: 0 1px 2px -1px rgba(0, 0, 0, .6), 0 10px 22px -8px rgba(0, 0, 0, .55);
  --line: #2a3237;
  --accent: #ffffff;
  --shade: #1b2126;
  --credit-grund: rgba(255, 255, 255, .92);
  --credit-ink: #000000;
  --polaroid-rahmen: #e0e0dc;
  --polaroid-schatten: none;
  --polaroid-rahmen-unten: #d6d6d1;
  --polaroid-seite: rgba(0, 0, 0, .10);
  --polaroid-band: rgba(0, 0, 0, .06);
  --polaroid-kante: rgba(0, 0, 0, .30);
  --polaroid-bild-schatten: inset 0 1px 3px rgba(0, 0, 0, .55), inset 0 0 0 1px rgba(0, 0, 0, .25);
  --polaroid-glanz: rgba(255, 255, 255, .07);
  --chevron: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17' fill='none' stroke='%23ffffff' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'><path d='M4.6 6.8 8.5 10.6 12.4 6.8'/></svg>");
  --state-wait-bg: #38311c;
  --state-wait-ink: #e4d2a4;
  --state-live-bg: #1e2e1c;
  --state-live-ink: #bdd9b9;
  --state-stop-bg: #382126;
  --state-stop-ink: #e9b9c0;
  --glocke-punkt: #ff6a5a;
  --chart: #55965b;
}


* { box-sizing: border-box; }
/**
 * **`hidden` bedeutet weg.**
 *
 * Der Browser setzt dafuer `display: none` - aber jede eigene `display`-Regel
 * ueberstimmt das, weil sie spezifischer ist. Bei einer Veranstaltung nahm die
 * versteckte Wetterzeile deshalb weiter ihren Abstand ein: unsichtbar, aber
 * nicht weg. Diese Zeile stellt es fuer alle Bauteile klar - und `!important`
 * ist hier richtig, weil es keinen Fall gibt, in dem `hidden` etwas anderes
 * heissen soll.
 */
[hidden] { display: none !important; }
/**
 * ===========================================================================
 * **EIN VERWEIS IST SCHWARZ UND UNTERSTRICHEN** - einmal, global
 * ===========================================================================
 *
 * Bis zum 04.09.2026 gab es diese Regel **nirgends**: Ein `<a>` ohne Klasse
 * war blau, wie der Browser ihn liefert, und jedes Bauteil setzte seine eigene
 * Fassung - `.bk-inhalt a`, `.place .where a`, `.wie-link`,
 * und in der Bilderschicht ein blauer Verweis auf die Teilnahmebedingungen
 * mitten in schwarzer Schrift. Dreizehn Stellen mit derselben Absicht und
 * dreizehn kleinen Abweichungen.
 *
 * Jetzt steht sie hier: **schwarz, unterstrichen, beim Zeigen dicker.** Der
 * Unterstrich ist die Form des Verweises im Fliesstext - er soll dort auch
 * ohne Farbe zu erkennen sein.
 *
 * **Was kein Verweis im Text ist, traegt keinen Strich.** Ein Knopf, eine
 * Kachel, eine Zeile der Huelle, der Fuss: Sie sind Flaechen, die man
 * anklickt, und ein Unterstrich darin sieht aus wie ein Fehler. Die Liste
 * darunter ist deshalb keine Ausnahmensammlung, sondern die Grenze zwischen
 * **Text** und **Bedienung** - und sie steht an derselben Stelle wie die Regel,
 * damit man beim Lesen sieht, wo sie endet.
 */
a {
  color: var(--strong);
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .16em;
}
a:hover, a:focus-visible { text-decoration-thickness: 2px; }
.action,
.backsquare,
.chrome-nav a,
.foot a,
.card a,
.card-visual,
.nav-row,
.nav-konto-zeile,
.nav-brand,
.textlink,
.photo-link,
.reiter,
.hb-nav a,
.bk-nav a {
  text-decoration: none;
}
/* Und im Fliesstext dieser Flaechen gilt die Regel wieder - eine Kachel ohne
   Strich kann einen Satz mit einem Verweis darin enthalten. */
.card p a { text-decoration: underline; }

body {
  margin: 0; background: var(--paper); color: var(--ink);
  /* 1 rem and not 16 px: the base type follows `html` - the footer's text
     size and the browser's zoom both grow it with everything else in rem.
     As a pixel value it would stay put. */
  font: 1rem/1.55 var(--font);
}
/* Header und Footer laufen über die volle Breite, ihr Inhalt bleibt beim
   Rahmen (`--rahmen-breite`) - wie bei tirol.at. Ohne Änderung am Markup: die Kinder bekommen die Breite. */
/* Abstand nach oben, damit nichts hinter dem Navigationsblock und dem
   Zurueck-Quadrat beginnt. Die Buehnen der Startseite und der Ortsseiten liegen
   ausserhalb von `main` - sie sollen ja bis unter die Leiste laufen.

   **Auf dem Telefon derselbe Abstand.** Hier stand ein rem mehr fuer schmale
   Schirme, weil der Navigationsblock dort fast so breit ist wie der Schirm.
   Er ist es nicht mehr - und ein Vorsprung, den nichts mehr braucht, ist eine
   Stufe zwischen zwei Breiten ohne Bedeutung. */
main { max-width: var(--rahmen-breite); margin: 0 auto; padding: 1.6rem var(--inset) 0; }
/* **Es gibt ein Mass, und das ist der Rahmen** (`--rahmen-breite`, 1100 px). Auch die vier Seiten, auf denen man
   blaettert statt liest (Startseite, Ergebnisseite, Ortsseite, Magazin), gehen
   nicht weiter hinaus.

   Ein zweites, breiteres Mass hatte genau einen Grund: eine **dritte** Kachel
   je Reihe, die im 1100er Rahmen zu schmal geworden waere. Die Reihe bricht
   bei zwei, also ist der Grund weg - und ein zweiter Rahmen ohne Grund ist
   eine Kante, die auf jeder dieser Seiten anders laeuft als Fuss,
   Gattungsband und Kopfzeile. */
header, footer { width: 100%; }
header > * { max-width: var(--rahmen-breite); margin-left: auto; margin-right: auto; padding: 0 1.25rem; }
header { margin-bottom: 1.6rem; padding-top: .2rem; }
/* ---------------------------------------------------------------------------
   Der Fuss - nach der Vorlage von tirol.at, in Schwarz.

   Oben die Netzwerke, darunter zwei Spalten mit viel Luft: links Kontakt und
   Pflichtseiten, rechts "Infos & Stories". Jede Zeile traegt ihr Zeichen an der
   rechten Spaltenkante - Pfeil nach rechts bleibt im Guide, schraeger Pfeil
   fuehrt hinaus.
   --------------------------------------------------------------------------- */
footer.foot {
  background: var(--nav); color: var(--nav-ink);
  border: 0;
  /* Die Schraege schneidet oben links ab; darunter scheint die Seite durch. */
  clip-path: polygon(0 5vw, 100% 0, 100% 100%, 0 100%);
  /* `--fuss-unter` is how far the footer slides under what stands above it -
     zero, except below the polaroids. The padding grows by the same amount,
     so the social icons keep their distance from the slant either way. */
  --fuss-unter: 0rem;
  /* `--fuss-luft` is the air between the slant and the first line. On the
     screen the slant itself is wide (5vw), so less air on top of it. */
  --fuss-luft: 4rem;
  margin-top: calc(3.5rem - var(--fuss-unter));
  padding: calc(5vw + var(--fuss-unter) + var(--fuss-luft)) 0 2.6rem;
  /**
   * **Die Hoehenlinien liegen dahinter** - dieselbe Datei wie im Theme
   * (`assets/images/topographic-map.svg`), hier als `web/hoehenlinien.svg`.
   *
   * Die Linien im SVG sind **weiss mit 15 Prozent Deckung**: Sie werden nur auf
   * dunklem Grund sichtbar, und genau dafuer sind sie gemacht. Deshalb steht
   * die Farbe zuerst und das Bild darueber - keine zweite Fassung fuer hell.
   *
   * `cover` und `center`: Das Muster ist eine Flaeche, kein Motiv; es darf
   * beschnitten werden, aber nicht kacheln - eine sichtbare Wiederholung waere
   * ein Raster und keine Landschaft.
   */
  background-image: url("hoehenlinien.svg");
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
}
@media (min-width: 64rem) {
  footer.foot { --fuss-luft: 1.5rem; }
}
footer.foot .foot-inner {
  max-width: var(--rahmen-breite); margin: 0 auto; padding: 0 1.25rem;
  display: grid; gap: 3.2rem;
}

/* Die Zeichen der Netzwerke sind flaechenbasiert (wie im Theme) - die Farbe
   kommt aus `fill`, nicht aus `stroke`. */
.foot-social { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 1.1rem; }
.foot-social a { display: inline-flex; padding: .2rem; }
.foot-icon { width: 1.15rem; height: 1.15rem; fill: color-mix(in srgb, var(--nav-ink) 80%, transparent); }
.foot-social a:hover .foot-icon, .foot-social a:focus-visible .foot-icon { fill: var(--nav-ink); }

/**
 * **Das Aufnaeher-Zeichen am rechten Ende der Netzwerkzeile** - nur auf dem
 * Desktop.
 *
 * Es ist viermal so gross wie die Zeichen daneben (1.15rem x 4): gross genug,
 * um die Marke zu sein, und klein genug, um die Zeile nicht zu sprengen. Auf
 * dem Telefon faellt es weg - dort ist die Zeile schon voll, und ein Zeichen,
 * das umbricht, steht nicht mehr am Rand, sondern im Weg.
 *
 * Als **Maske** und nicht als Bild: So nimmt das Zeichen `--nav-ink` an und
 * stimmt in hell, dunkel und System, ohne zwei Dateien und ohne eine Regel, die
 * weiss, welcher Zustand gerade gilt. Dieselbe Ueberlegung wie bei den
 * Netzwerkzeichen, die ihre Farbe aus `fill` beziehen.
 *
 * **Die Quelle muss die weisse Fassung sein** (`logo_bfp-patch-white.svg`).
 * Eine Maske liest die Deckung, nicht die Farbe - und die schwarze Fassung ist
 * eine schwarze Scheibe mit weisser Zeichnung darauf. Ihre Deckung ist damit
 * der volle Kreis, und genau das war zu sehen: eine hellgraue Kreisflaeche
 * ohne Zeichen. Die weisse Fassung hat keinen Grund, nur die Zeichnung - 36 %
 * der Flaeche statt 73 %.
 */
.foot-line { display: flex; align-items: center; justify-content: space-between; gap: 1.1rem; }
.foot-patch { display: none; }
@media (min-width: 46rem) {
  /**
   * **Am rechten Rand** - so entschieden am 03.09.2026, nachdem es kurz an der
   * rechten Spalte darunter ausgerichtet stand.
   *
   * Das Raster des Fusses waere die naheliegende Kante gewesen, aber das
   * Zeichen gehoert nicht in eine der beiden Spalten: Es ist die Absendermarke
   * der ganzen Seite, und die steht aussen. Die Netzwerkzeichen links, das
   * Zeichen rechts - die Zeile spannt damit den Rahmen auf, in dem alles
   * andere darunter liegt.
   */
  .foot-patch {
    display: block; flex: none;
    width: 4.6rem; height: 4.6rem;
    /* Full ink, not a mix: on the black footer that is white, and the patch is
       the sender's mark - greyed down it read as a disabled icon. */
    background: var(--nav-ink);
    -webkit-mask: url(logo-patch.svg) center / contain no-repeat;
    mask: url(logo-patch.svg) center / contain no-repeat;
  }
}

.foot-two { display: grid; gap: 2.6rem; }
/* Untereinander steht „Infos & Stories" **zuerst**: Newsletter, Magazin, Merch
   sind Wege weiter ins Angebot, Impressum und Datenschutz sind der Abschluss.
   Nebeneinander liest man beide Spalten gleichzeitig, da bleibt Kontakt links. */
/* **Nach dem Namen, nicht nach der Position.** `:last-child` traf seit dem
   Themenblock nicht mehr "Infos & Stories", sondern die Themen - der Fuss
   stand damit auf dem Telefon in der falschen Reihenfolge, und der Block
   sprang beim Nachladen an den Anfang. */
.foot-two > #foot-infos { order: -1; }
@media (min-width: 46rem) {
  /* Drei Spalten, sobald es die Themen gibt - `:has` fragt das Dokument, nicht
     das Skript: Fehlt der Block (keine Themenseite), bleiben es zwei. */
  .foot-two { grid-template-columns: 1fr 1fr; gap: 3rem 4rem; }
  .foot-two:has(#foot-topics:not([hidden])) { grid-template-columns: repeat(3, 1fr); }
  .foot-two > #foot-infos { order: 0; }
}
/* Die Ueberschrift ist fett und so gross wie die Zeilen darunter - kein
   Kleingedrucktes in Grossbuchstaben. */
.foot-title { margin: 0 0 1.6rem; font-size: 1.05rem; font-weight: 700; }
/* **Die zweite Ueberschrift in derselben Spalte** (10.09.2026): Unter den
   Themen stehen die Orte - beides Wege in den Bestand, die quer zur Taxonomie
   liegen, und beide gehoeren deshalb in dieselbe Spalte. Sie braucht Luft nach
   oben, sonst klebt sie an der letzten Zeile darueber; eine eigene Spalte
   waere bei vier Gemeinden eine halbe leere. */
.foot-title-zwei { margin-top: 2rem; }
.foot-block ul { list-style: none; margin: 0; padding: 0; }

/* Eine Zeile: Text links, Zeichen rechts an der Spaltenkante. Die ganze Zeile
   ist die Klickflaeche - ein Pfeil allein ist ein zu kleines Ziel. */
/**
 * **Beide Spalten haben denselben Zeilenabstand.**
 *
 * Vorher stand links 0.98rem und rechts 1.05rem, dazu unterschiedliche
 * Zeilenhoehen aus der Schriftart heraus: 42 gegen 44 Pixel je Zeile. Bei der
 * ersten Zeile faellt das nicht auf, bei der vierten stehen die Spalten
 * dreissig Pixel auseinander - und der Fuss sieht aus, als waere er
 * zusammengeschoben.
 *
 * Die Groesse ist deshalb hier festgelegt und die Zeilenhoehe **fest**
 * (`line-height: 1.5`, kein `normal`): So bestimmt die Schriftart die Hoehe
 * nicht mehr mit. Der Unterschied zwischen den Spalten bleibt trotzdem
 * sichtbar - er liegt im Schriftschnitt (fett rechts), und der aendert die
 * Hoehe nicht.
 */
.foot-row { font-size: 1rem; }
.foot-row > a, .foot-row > span:first-child {
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  padding: .55rem 0; line-height: 1.5; text-decoration: none;
  /* **Etwas graeulicher als die Ueberschrift.** Die Ueberschrift steht in
     vollem Weiss, die Zeilen darunter gedaempft: So ist auf einen Blick zu
     sehen, was Titel ist und was Weg. Bei gleicher Helligkeit verschwimmt die
     Spalte zu einer Liste ohne Kopf. Beim Zeigen wird die Zeile hell - dann
     ist sie das, worauf man gerade zielt. */
  color: color-mix(in srgb, var(--nav-ink) 68%, transparent);
}
/* Beim Zeigen wird die Zeile **hell** - und nicht unterstrichen. Der Wechsel
   von gedaempft zu weiss ist im Footer die deutlichere Antwort: Eine Linie
   unter einer Zeile, die ohnehin ihre eigene Reihe hat, ist Zierde. */
.foot-row a:hover, .foot-row a:focus-visible { color: var(--nav-ink); }
.foot-row-icon { width: 1.05rem; height: 1.05rem; flex: none; }
/* Die rechte Spalte steht fett - dort liegen die Wege, nicht die Pflichten.
   **Nur fett, nicht groesser:** Die Groesse bestimmt den Zeilenabstand, und der
   muss in beiden Spalten derselbe sein. */
.foot-strong .foot-row { font-weight: 700; }


/* **The build stamp** - the last line of the footer, in the footer's own
   small type: it says which version is served. */
/* The last row of the footer: light/dark, text size, then the version.
   It wraps on a phone instead of running out of the frame. */
.foot-unten { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1.5rem; margin: 0; }
/* **Light/dark carries its word before the sign** - the word is its name.
   The text size beside it: word, minus, value, plus - in the footer's small
   type and its muted ink, like the stamp. */
/* The same small type as the stamp beside them - one row, one size. */
.foot-thema, .foot-schrift { font-size: .82rem; line-height: 1.55; }
/* **Only the sign sits on a ground** - the word before it is its label, not
   part of the round shape. The signs carry a faint ground at rest, so they
   read as buttons, and a stronger one under the pointer and in focus. */
.foot-thema {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: 0; border: 0; background: none;
  color: color-mix(in srgb, var(--nav-ink) 70%, transparent);
  font-family: inherit; cursor: pointer;
}
.foot-schrift {
  display: inline-flex; align-items: center; gap: .3rem;
  color: color-mix(in srgb, var(--nav-ink) 70%, transparent);
}
.foot-schrift > span { margin-right: .2rem; }
.foot-schrift-wert { min-width: 3.4em; text-align: center; font-variant-numeric: tabular-nums; }
.foot-zeichen, .foot-schrift-knopf {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 2rem; height: 2rem; padding: 0; border: 0; border-radius: 50%;
  background: color-mix(in srgb, var(--nav-ink) 10%, transparent);
  color: inherit; cursor: pointer;
  /* A change of colour, not a movement - no rule for reduced motion. */
  transition: background-color .15s, color .15s;
}
.foot-thema:hover, .foot-thema:focus-visible,
.foot-schrift-knopf:hover:not(:disabled), .foot-schrift-knopf:focus-visible { color: var(--nav-ink); }
.foot-thema:hover .foot-zeichen, .foot-thema:focus-visible .foot-zeichen,
.foot-schrift-knopf:hover:not(:disabled), .foot-schrift-knopf:focus-visible {
  background: color-mix(in srgb, var(--nav-ink) 22%, transparent);
}
.foot-thema:focus-visible .foot-zeichen, .foot-schrift-knopf:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: 2px; }
.foot-thema:focus-visible { outline: none; }
.foot-schrift-knopf:disabled { opacity: .35; cursor: default; }
.foot-zeichen .nav-icon, .foot-schrift-knopf .nav-icon { width: 1.05rem; height: 1.05rem; flex: none; }
@media (pointer: coarse) {
  .foot-zeichen, .foot-schrift-knopf { width: 2.75rem; height: 2.75rem; }
}
/* **The text size of the root** - set from the footer (`textSizeBind` in
   `chrome.js`). The guide is set in rem, so everything grows with it. The head
   of the page - the block with mark and menu, the magnifier and the way back -
   is set in `--chrome-rem`: on a wide screen that is the rem and grows along,
   on a phone it is one rem of the browser whatever the step (`--text-scale`
   undoes it). There they share one row, and grown they ran into each other. */
html { --text-scale: 1; --chrome-rem: 1rem; }
html[data-text-size="112.5"] { font-size: 112.5%; --text-scale: 1.125; }
html[data-text-size="125"] { font-size: 125%; --text-scale: 1.25; }
html[data-text-size="137.5"] { font-size: 137.5%; --text-scale: 1.375; }
html[data-text-size="150"] { font-size: 150%; --text-scale: 1.5; }
/* **On a phone the steps end at 125 %** - above it a line holds three words.
   A larger step chosen on a wide screen counts as 125 % here (`TEXT_SIZE_PHONE`
   in `chrome.js` says the same to the buttons). */
@media (max-width: 45.99rem) {
  html { --chrome-rem: calc(1rem / var(--text-scale)); }
  html[data-text-size="137.5"], html[data-text-size="150"] { font-size: 125%; --text-scale: 1.25; }
}
.foot-stand {
  margin: 0;
  font-size: .82rem; line-height: 1.55;
  color: color-mix(in srgb, var(--nav-ink) 55%, transparent);
}

/* **Die Sprache im Footer.** Ein Griff, der aussieht wie eine Fusszeile und
   sich verhaelt wie ein Knopf: Zeichen, Name der Sprache, sonst nichts. */
.foot-lang {
  display: inline-flex; align-items: center; gap: .4rem;
  background: none; border: 0; padding: .4rem 0; cursor: pointer;
  font: inherit; font-size: .95rem; color: color-mix(in srgb, var(--nav-ink) 68%, transparent);
}
.foot-lang:hover, .foot-lang:focus-visible { color: var(--nav-ink); }
.foot-lang:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: 3px; }
.foot-lang .nav-icon { width: 1.05rem; height: 1.05rem; }
/* Die Flagge: ein kleiner Kreis vor dem Namen. Feste Groesse, damit die Zeile
   nicht springt, waehrend die Datei noch laedt. */
.flag { width: 1.15rem; height: 1.15rem; flex: none; border-radius: 50%; display: block; }
/* **Im Fuss so gross wie die Weltkugel daneben** (05.09.2026): Zwei runde
   Zeichen in einer Zeile, eines merklich groesser - das las sich wie ein
   Fehler. Jetzt beide 1,05 rem. */
.foot-lang .flag { width: 1.05rem; height: 1.05rem; }
/* **Die Flagge im Layer ist gemessen, nicht gewaehlt** (18.09.2026): Sechs
   Zeilen, ein Titel und die Polster des Kastens muessen in das Quadrat von
   30 rem passen - mit 1,4 rem Flagge, 1,15 rem Schrift und .9 rem Polster je
   Zeile waren es 31 rem, und das Quadrat bekam einen Rollbalken fuer eine
   Liste, die man **ganz** sehen soll. Jetzt sind es rund 26 rem. */
.langlayer .flag { width: 1.2rem; height: 1.2rem; }

/* Der Layer dahinter - dieselbe Bauart wie die Bildergalerie: ein `<dialog>`,
   weisser Grund, das schwarze Quadrat mit dem X in der Ecke. Eine Sprache ist
   keine Einstellung unter vielen, sondern die Fassung, in der man liest; ein
   Layer haelt kurz an und fragt, eine Aufklappliste tut das nicht. */
.langlayer {
  position: fixed; inset: 0; width: auto; height: auto;
  max-width: none; max-height: none; border: 0; padding: 0; margin: 0;
  background: var(--paper); color: var(--ink); display: none;
}
/**
 * **Der Inhalt steht oben, nicht in der Mitte.**
 *
 * Senkrecht zentriert sah eine kurze Liste aus wie ein Versehen: Auf dem
 * Vollbild der schmalen Fassung lagen ueber „Wo suchst du?" rund 230 leere
 * Pixel, und wer im Suchfeld tippt, sieht seine Treffer nach unten wandern,
 * weil die Mitte mitwandert. Oben steht der Anfang da, wo er hingehoert, und
 * die Liste waechst nach unten, ohne dass sich etwas anderes bewegt.
 *
 * Waagerecht bleibt es mittig - das ist die Spalte, nicht die Lage.
 *
 * Der Abstand nach oben ist das schwarze Quadrat mit dem X
 * (`--navheight`, 3,7 rem) plus Luft: Darunter faengt der Text an, statt
 * daneben zu stossen.
 */
.langlayer[open] {
  display: grid; align-content: start; justify-items: center;
  padding-block: calc(var(--navheight, 3.7rem) + 1.2rem) 2.5rem;
}
.langlayer::backdrop { background: color-mix(in srgb, var(--paper) 92%, transparent); }
.langlayer-close { position: absolute; top: 0; right: 0; }
.langlayer-inner { width: min(24rem, calc(100% - 3rem)); }
/* **In normaler Schreibweise.** Versalien mit Sperrung waren eine zweite
   Typografie fuer ein einziges Wort - und ein Wort, das man in Grossbuchstaben
   setzt, liest sich lauter, als es gemeint ist. Es ist eine Ueberschrift ueber
   vier Zeilen, kein Signal. */
.langlayer-title {
  margin: 0 0 1rem; font-size: .95rem;
  color: var(--soft);
}
.langlayer ul { list-style: none; margin: 0; padding: 0; }
.langlayer li + li { border-top: 1px solid var(--line); }
.langlayer a {
  display: flex; align-items: center; gap: .8rem;
  padding: .55rem .2rem; color: var(--ink); text-decoration: none; font-size: 1.05rem;
}
.langlayer a > span { flex: 1; }
.langlayer a:hover, .langlayer a:focus-visible { background: var(--shade); }
.langlayer a[aria-current="true"] { font-weight: 700; }
/* **Ohne Zeigegeraet bleibt die Zeile gross.** Das enge Mass oben ist die
   Antwort auf das Quadrat am Schirm; auf dem Telefon ist die Schicht der ganze
   Bildschirm, dort gibt es den Platzmangel nicht - und ein Daumen trifft
   44 px, keine 43. */
@media (pointer: coarse) {
  .langlayer a { padding: .8rem .2rem; }
}
/* Das Haekchen an der gewaehlten Sprache - eine Spur groesser als die
   Grundgroesse der Zeichen, damit es die Zeile abschliesst und nicht nur
   danebensteht. */
.langlayer a .nav-icon { width: 1.15rem; height: 1.15rem; }

/**
 * **On a screen a box in the middle, as tall as its content.**
 *
 * On a phone a layer is the whole screen, because there is no other. On a
 * screen the same would let a choice of three lines clear a 27-inch monitor.
 * The action is small, so the surface is small - and it ends where its list
 * ends: a fixed square left a band of empty paper under three languages.
 *
 * It is the same box as `.schicht`: black frame, light ground, a dark ground
 * behind it instead of almost opaque paper - so it lies visibly **on** the
 * page instead of replacing it. The place picker shares the construction
 * (`class="placelayer langlayer"`, `app.js`) and may grow wider.
 */
@media (min-width: 48rem) {
  .langlayer {
    inset: 0; margin: auto;
    /**
     * **`fit-content`, not `auto`** - the difference between "as tall as the
     * content" and "stretch". A fixed element with `inset: 0` has a top
     * **and** a bottom edge; with `height: auto` the browser derives the
     * height from both and fills the space. `fit-content` takes the measure
     * from the content, and `margin: auto` centres it - both work because
     * `inset: 0` knows both edges. `max-height` keeps a long list inside the
     * window.
     */
    width: min(30rem, 90vw); height: fit-content; max-height: 90vh;
    border: 1px solid var(--strong);
  }
  .langlayer::backdrop { background: rgb(0 0 0 / .55); }
  .langlayer-inner { width: min(20rem, calc(100% - 3rem)); }
  .placelayer.langlayer .langlayer-inner { width: calc(100% - 3rem); }
}

footer.foot .note {
  margin: 0; font-size: .78rem;
  color: color-mix(in srgb, var(--nav-ink) 55%, transparent);
}

/* Der Navigationsblock. **Nicht durchgezogen** - ein dunkler Block oben rechts,
   der an der Oberkante sitzt, und daneben Weiss. Ein Balken ueber die ganze
   Breite macht aus dem Kopf ein Band; ein Block macht daraus eine Ecke, in der
   die Navigation wohnt.

   Er traegt zwei Dinge: das Zeichen und den Knopf. Das Zeichen fuehrt nach Hause
   - das Wortzeichen GUIDE ist entfallen, und ein Kopf ohne Weg zurueck waere
   eine Sackgasse. Ins Magazin geht es aus dem Aufklapper. */
/* **Klebend, und ganz rechts.**
   Der Block bleibt beim Scrollen oben stehen. Damit das ueber die ganze Seite
   gilt, sitzt er als eigenes Kind des Dokuments neben dem Kopf und nicht darin -
   ein klebendes Element klebt nur, solange sein umgebender Kasten sichtbar ist.

   Der klebende Rahmen laeuft ueber die volle Breite, weil der Aufklapper sie
   braucht. Damit er nicht die oberen 70 Pixel der Seite gegen Klicks abschirmt,
   nimmt er selbst keine Klicks an - nur seine Kinder tun es. */
.chrome-nav {
  position: sticky; top: 0; z-index: 20; pointer-events: none;
  /* Die Hoehe des Blocks steht an **einer** Stelle. Der Layer setzt sein X mit
     demselben Wert, damit es genau dort erscheint, wo der Hamburger war - zwei
     getippte Zahlen waeren zwei Zahlen, die irgendwann auseinandergehen. */
  --navpad: calc(.8 * var(--chrome-rem));
}
/* Klicks nehmen **nur** die beiden Kaesten an, die wirklich etwas tun. Auf die
   Zwischenschichten (`.navbar`, `.bar`) darf es nicht zurueckgesetzt werden:
   Die laufen ueber die volle Breite, und dann liegt eine unsichtbare Platte von
   70 Pixeln Hoehe ueber dem Anfang der Seite. */
.chrome-nav .nav, .chrome-nav .nav-layer { pointer-events: auto; }
/* Ganz rechts heisst an der Fensterkante, nicht an der Textkante: Der Block
   haengt an der Ecke des Bildschirms, nicht an der Spalte des Inhalts. */
.navbar { padding: 0; }
.navbar > .bar { max-width: none; }
.bar { display: flex; justify-content: flex-end; }
.claim { color: var(--soft); font-size: .85rem; margin: 1rem 0 1.2rem; }

/* Im Block nur zwei Dinge: das Zeichen und der Knopf. Die Wege stehen im
   Aufklapper - eine Leiste mit sechs Beschriftungen ist eine Liste, kein Kopf. */
/* **Enger um das Zeichen** (04.09.2026): Der schwarze Kasten trug links und
   rechts 1,25 rem und zwischen Zeichen und Knopf 1,1 rem - zusammen mehr Luft
   als das Zeichen hoch ist, und der Kasten wirkte dadurch breiter als sein
   Inhalt. Jetzt .8 rem aussen und .7 rem dazwischen: Zeichen und Knopf
   gehoeren sichtbar zusammen, ohne sich zu beruehren. */
.nav {
  display: flex; align-items: center; gap: calc(.7 * var(--chrome-rem));
  background: var(--nav); padding: var(--navpad) calc(.8 * var(--chrome-rem));
}
.nav-brand { display: inline-flex; padding: calc(.2 * var(--chrome-rem)) calc(.3 * var(--chrome-rem)); }
/* Das Querzeichen der Marke. Ueber die Hoehe gesetzt, nicht ueber die Breite -
   das Verhaeltnis ist 272 zu 32, und eine Breitenangabe macht es auf dem Telefon
   entweder winzig oder zu breit fuer die Leiste. */
.nav-logo { height: calc(1.15 * var(--chrome-rem)); width: auto; fill: var(--nav-ink); display: block; }
.nav-brand:hover .nav-logo, .nav-brand:focus-visible .nav-logo {
  fill: color-mix(in srgb, var(--nav-ink) 70%, transparent);
}
.nav-brand:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: -2px; }
.nav-link {
  display: inline-flex; align-items: center; gap: calc(.35 * var(--chrome-rem));
  color: color-mix(in srgb, var(--nav-ink) 88%, transparent); text-decoration: none;
  font-size: calc(.82 * var(--chrome-rem)); padding: calc(.4 * var(--chrome-rem)) calc(.55 * var(--chrome-rem));
  background: none; border: 0; cursor: pointer; font-family: inherit;
}
.nav-link:hover, .nav-link:focus-visible {
  color: var(--nav-ink); background: color-mix(in srgb, var(--nav-ink) 12%, transparent);
}
.nav-link[aria-current="page"] { color: var(--paper); box-shadow: inset 0 -2px 0 var(--paper); }
.nav-link:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: -2px; }
.nav-icon { width: 1rem; height: 1rem; flex: none; }
.nav-link .nav-icon, .backsquare .nav-icon { width: var(--chrome-rem); height: var(--chrome-rem); }

/* Der Aufklapper: die ganze Navigation. Suchfeld oben, darunter die Gattungen in
   vier Spalten, unten die uebrigen Wege und die Sprache. Er laeuft ueber die
   volle Breite wie die Leiste, sein Inhalt bleibt bei 1100. */
/* Der Layer: die ganze Navigation, vollflaechig, auf demselben Grund wie die
   Leiste. Beide dieselbe Farbe - dadurch ist der Vorgang nicht "Kasten oeffnet
   sich ueber der Seite", sondern "die dunkle Ecke waechst auf den ganzen
   Schirm".

   Er scrollt in sich; `overscroll-behavior` haelt das Rad drin, damit die Seite
   dahinter nicht mitwandert. */
/* **Ein Drittel der Breite, an der rechten Kante** (so ab 03.09.2026). Der
   Aufklapper ist eine Spalte mit grossen Zeilen; ueber die ganze Fensterbreite
   waere er eine Liste mit sehr viel Luft daneben. Auf dem Telefon nimmt er alles
   - dort ist ein Drittel keine Spalte, sondern ein Streifen. */
.nav-layer {
  position: fixed; inset: 0 0 0 auto; z-index: 30;
  width: 100%;
  /* Spalte, damit die Kontozeile unten mit `margin-top: auto` an den Rand
     kann - und dort bleibt, wenn der Aufklapper die Ebene wechselt. */
  display: flex; flex-direction: column;
  background: var(--nav); color: var(--nav-ink);
  overflow-y: auto; overscroll-behavior: contain;
  /* Verborgen, aber im Dokument: `visibility` nimmt ihn aus dem Griffweg und
     aus dem Vorleseprogramm, laesst ihn aber seine Bewegung zeigen. */
  visibility: hidden; opacity: 0;
  transition: opacity .22s ease, visibility .22s;
  /* Its width decides whether a rubric and its pill share a line - not the
     window's (`@container navlayer` below). */
  container: navlayer / inline-size;
}
/* 30 rem on a screen: the widest rubric with its pill ("Übernachten" +
   "Hotel, FeWo & Camping", 322 px measured) needs about 29 rem of layer. */
@media (min-width: 52rem) {
  .nav-layer { width: max(30rem, 33.333%); }
}
.chrome-nav[data-open="true"] .nav-layer { visibility: visible; opacity: 1; }
/* Die Leiste faehrt nach oben aus dem Bild. Sie liegt unter dem Layer, ist also
   nicht mehr zu sehen - die Bewegung ist trotzdem richtig: Nach dem Schliessen
   faehrt sie sichtbar zurueck. */
.navbar { transition: transform .22s ease; }
.chrome-nav[data-open="true"] .navbar { transform: translateY(-100%); }
/* Die Zeile mit dem X - dieselbe Hoehe und derselbe Innenabstand wie die Leiste,
   damit das X genau dort steht, wo der Hamburger war.

   Das Zeichen steht in beiden Knoepfen **hinter** dem Wort. Vor dem Wort haengt
   seine Lage an der Wortbreite, und "Schliessen" ist breiter als "Menue" - das
   Zeichen waere beim Umschalten um dreizehn Pixel gesprungen. Hinten haengt es
   an der rechten Kante, und die ist bei beiden dieselbe. */
.nav-layer-top {
  display: flex; justify-content: flex-end; align-items: center;
  /* Derselbe Innenabstand wie in der Leiste: Das X muss genau dort stehen, wo
     der Hamburger stand - deshalb 1.25 hier und ebenso an den Ebenen. */
  padding: var(--navpad) calc(1.25 * var(--chrome-rem));
}
.nav-panel-inner {
  /**
   * **Seitlich kein Innenabstand** - der sitzt an den Ebenen selbst.
   *
   * `overflow: hidden` schneidet an der **Polsterkante** ab, nicht am Text: Mit
   * 20 Pixeln Polster links blieben von Ebene 1 genau diese 20 Pixel stehen,
   * wenn Ebene 2 hereingeschoben war - und dort sassen ihre Pfeile. Im Bild sah
   * es aus wie ein zweiter Pfeil an jeder Zeile der zweiten Ebene.
   */
  padding: .5rem 0 3rem;
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
   Zwei Ebenen, eine Spalte.
   ---------------------------------------------------------------------------

   Ebene 1 sind die Rubriken, Ebene 2 die Gattungen darunter. Beide liegen
   nebeneinander in einem Streifen der doppelten Breite; geschaltet wird ein
   Attribut (`data-level`), und die Bewegung macht CSS. Kein Ein- und Ausblenden
   zweier Listen: Wo der Streifen steht, ist auch der Weg zurueck - und das ist
   genau die Aussage der Bewegung. */
.nav-drill {
  display: flex; width: 200%;
  transition: transform .26s ease;
}
.nav-drill[data-level="2"] { transform: translateX(-50%); }

/* **Verschoben ist nicht verborgen** (07.09.2026).

   Bis die Navigation gebaut wurde, entstand Ebene 2 im Moment des Klicks - was
   nicht dastand, konnte auch nicht im Weg sein. Jetzt stehen **beide** Ebenen
   im Dokument, und `transform` schiebt die eine nur aus dem Bild: Fuer die
   Tabulatortaste und fuer ein Vorleseprogramm bleibt sie da. Man tabbt sonst
   aus den Rubriken heraus in die Gattungslinks der abgeschobenen Spalte.

   **Denselben Fehler gab es vorher schon** - `nav-drill-back` setzte die Ebene
   zurueck, ohne den Inhalt abzuraeumen. Wer einmal in eine Rubrik ging und
   zurueck, tabbte danach in ihre Links.

   `visibility` und nicht `display`: Die Spalte muss ihre Breite behalten,
   `translateX(-50%)` rechnet gegen den Streifen. Es ist dasselbe Werkzeug mit
   derselben Begruendung, die schon an `.nav-layer` steht.

   **Die Uebergangszeile ist Pflicht, nicht Zierde.** Ohne sie springt
   `visibility` sofort um, und Ebene 1 verschwindet mitten in der Bewegung. Mit
   Dauer flippt sie beim Ausblenden am Ende und beim Einblenden am Anfang -
   richtig in beide Richtungen. */
.nav-drill[data-level="1"] .nav-level-2,
.nav-drill[data-level="2"] .nav-level-1 { visibility: hidden; }
.nav-level { transition: visibility .26s; }
/* Jede Ebene ist genau die halbe Streifenbreite - also die volle Spaltenbreite.
   Mit `grid-template-columns: 100% 100%` waren es zweimal die **ganze**
   Streifenbreite: Die Prozente rechnen gegen den Kasten selbst, und der ist hier
   doppelt so breit wie die Spalte. Die zweite Ebene lag damit ausserhalb. */
/**
 * Jede Ebene ist genau die halbe Streifenbreite - also die volle Spaltenbreite -
 * **und traegt ihren Innenabstand selbst.**
 *
 * Am Kasten darum darf er nicht sitzen: `overflow: hidden` schneidet an der
 * Polsterkante ab, und die 20 Pixel Polster liessen genau den rechten Rand von
 * Ebene 1 stehen - dort, wo ihre Pfeile sind.
 *
 * Die Reihenfolge ist hier wichtig: `.nav-level-1` **ist** die Liste (ein `ul`).
 * Ein `padding: 0` in derselben Regelgruppe hat den Innenabstand vorher wieder
 * eingesammelt, und die Zeilen klebten an der Kante. Deshalb setzt die Regel
 * fuer Listen nur noch, was eine Liste braucht.
 */
.nav-level { width: 50%; flex: none; min-width: 0; padding: 0 1.25rem; }
.nav-level, .nav-level ul { list-style: none; margin: 0; }
.nav-level ul { padding: 0; }

/* Die grosse Zeile - Rubrik oder Weg zurueck. Sie fuellt die Spalte, damit man
   sie auf einem Telefon nicht treffen muss, sondern nur tippen. */
/* **Nicht fett.** Die Zeile ist ohnehin die groesste auf der Flaeche; Fettdruck
   dazu macht aus einer Ordnung eine Ansage. Gross **und** fett war zweimal
   dasselbe Argument. */
.nav-row {
  display: flex; align-items: center; gap: .7rem; width: 100%;
  background: none; border: 0; padding: .9rem 0; cursor: pointer;
  font: inherit; font-size: clamp(1.25rem, 3.6vw, 1.6rem); font-weight: 400; line-height: 1.2;
  color: var(--nav-ink); text-align: left;
}
.nav-row > span { flex: 1; }
/* **Every row the same form: the name, under it the pill at the right edge.**
   Beside the word it fitted in some rows and wrapped in others - two shapes
   in one list, and that was the unrest. Now each pill stands on the same
   edge, in the same line of its row. */
.nav-row-text { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.nav-beispiele {
  /* On the phone under the name and flush with it; in a wide layer on the
     same line at the right edge (see below). */
  align-self: flex-start;
  padding: .25rem .75rem; border-radius: 999px;
  background: color-mix(in srgb, var(--nav-ink) 14%, transparent);
  color: color-mix(in srgb, var(--nav-ink) 62%, transparent);
  font-family: var(--mono); font-size: .68rem; line-height: 1.4; font-weight: 400;
  white-space: nowrap;
}
/* From a layer of 29 rem the name and its pill share one line, the pill at the
   right edge before the arrow; below that there is no room, and the pill takes
   its own line under the name. Should a long translation still not fit, the
   pill is cut with an ellipsis rather than run under the arrow - its full text
   stays in the title. */
@container navlayer (min-width: 29rem) {
  .nav-row-text { flex-direction: row; align-items: center; gap: .6rem; }
  .nav-beispiele {
    margin-left: auto; align-self: center;
    min-width: 0; overflow: hidden; text-overflow: ellipsis;
  }
  .nav-row-text > span:first-child { flex: none; }
}
/* On the second level the pill stands beside the name - the row there is the
   way back and has no arrow on the right to line up with. */
.nav-row-neben { flex-direction: row; flex-wrap: wrap; align-items: center; gap: .3rem .6rem; }
.nav-row-neben .nav-beispiele { align-self: center; }
/* Der Pfeil etwas groesser als das Wort: Er ist die Handlung der Zeile, nicht
   ihre Fussnote.

   **Und er haelt Abstand zur Kante** (04.09.2026): Er stand buendig an der
   rechten Kante des Aufklappers, und beim Zeigen wandert er noch .2 rem
   weiter - dort war er dann fast draussen. Ein halbes rem Luft, und die
   Bewegung hat wieder Platz. */
.nav-row .nav-icon {
  width: 1.35rem; height: 1.35rem; flex: none; transition: transform .18s;
  margin-right: .5rem;
}
.nav-row:hover .nav-icon { transform: translateX(.2rem); }
.nav-row:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: 2px; }

/* Die Kontozeile am Fuss des Aufklappers.

   **Sie sieht aus wie eine Zeile der Ebene 1, aber leiser.** Dieselbe Hoehe,
   derselbe Pfeil, dieselbe Farbe - nur kleiner gesetzt und mit einem Strich
   darueber. Der Strich sagt, dass hier etwas anderes anfaengt: Oben steht der
   Bestand, hier steht, wer man ist. Ohne ihn waere es die letzte Rubrik.

   Das Bild ist rund - dieselbe Ausnahme und derselbe Grund wie im Profil: Ein
   Portraet ist kein Element der Oberflaeche. */
.nav-konto {
  /**
   * **Senkrecht kein Innenabstand - der sitzt an der Zeile.**
   *
   * Vorher trugen ihn beide: 1rem aus `.nav-konto-zeile` und zusaetzlich
   * 1,25rem hier unten. Oben war der Abstand damit 1rem, unten 2,25rem, und
   * das sah aus wie ein Versehen, weil es eines war. Eine Sache, ein Ort: Die
   * Zeile ist das Bedienelement und bringt ihren Abstand selbst mit - der ist
   * gleichzeitig ihre Trefferflaeche und deshalb ohnehin nicht verzichtbar.
   */
  padding: 0 1.25rem;
  /* Ganz nach unten, unabhaengig davon, wie hoch der Aufklapper gerade ist. */
  margin-top: auto;
  border-top: 1px solid color-mix(in srgb, var(--nav-ink) 22%, transparent);
}
/* **Die Kontozeile ist die haeufigste im Aufklapper** - sie fuehrt ins Profil.
   Deshalb hoeher als die uebrigen: leichter zu treffen, ohne dass sie lauter
   waere (05.09.2026). */
.nav-konto-zeile {
  display: flex; align-items: center; gap: .8rem;
  /* **Hoeher als die uebrigen Zeilen** (05.09.2026): Sie ist der haeufigste
     Griff im Aufklapper - ins eigene Profil. Mehr Flaeche heisst schneller
     getroffen, ohne dass sie lauter waere: dieselbe Schrift, derselbe Grund. */
  padding: 1.4rem 0; min-height: 4.4rem;
  color: var(--nav-ink); text-decoration: none;
}
.nav-konto-bild {
  width: 2.4rem; height: 2.4rem; border-radius: 50%; flex: none;
  object-fit: cover; display: grid; place-items: center; overflow: hidden;
  font-size: .95rem; font-weight: 400; line-height: 1;
}
/**
 * Ohne Foto: **heller Kreis, dunkles Zeichen** - die Umkehrung der Leiste.
 *
 * Nicht `--paper` und `--strong` genommen, obwohl das im hellen Modus dasselbe
 * Weiss und Schwarz ergibt. Im dunklen Modus dreht die Navigation mit, und dann
 * waere ein weisser Kreis auf weissem Grund verschwunden. `--nav-ink` auf
 * `--nav` ist immer der Gegensatz zur Leiste, in beiden Richtungen.
 */
.nav-konto-leer {
  background: var(--nav-ink); color: var(--nav);
}
.nav-konto-leer .nav-icon { width: 1.4rem; height: 1.4rem; stroke-width: 1.5; }

/* Die drei Vorteile auf der Anmeldeseite.

   **Keine Kacheln, keine Rahmen.** Es sind drei Zeilen, nicht drei Angebote zur
   Wahl - ein Kasten um jede haette gesagt, man muesse sich entscheiden. Das
   Zeichen links, die Sache fett, der Grund darunter. */
.vorteile {
  list-style: none; margin: 0 0 2rem; padding: 0;
  display: grid; gap: 1rem;
}
.vorteile li { display: grid; grid-template-columns: auto 1fr; gap: .9rem; align-items: start; }
.vorteile svg { width: 1.5rem; height: 1.5rem; color: var(--strong); margin-top: .1rem; }
.vorteile span { display: grid; gap: .1rem; line-height: 1.35; }
.vorteile strong { font-weight: 700; }
.vorteile span { color: var(--soft); }
.vorteile strong { color: var(--ink); }

/* ==========================================================================
   Die Buecher der Dokumentation
   ==========================================================================

   Vier Bereiche benutzen diese Klassen - Handbuch, Technik, Styleguide, Hilfe.
   Sie unterscheiden sich im Inhalt, nicht in der Form: eine Gliederung, ein
   Text, ein Editor.

   **Eine Spalte, die Gliederung oben in einer Klappe** (08.09.2026). Vorher
   standen zwei Spalten nebeneinander, jede mit eigenem Rollkasten. Der Gewinn
   ist nicht der Fliesstext - der ist bei `--text` gedeckelt -, sondern die drei
   Faelle, in denen die Deckelung ausdruecklich aufgehoben ist: der Editor
   (+45 %), die Tabellen der Technik und die Mermaid-Diagramme.

   **Und die Seite hat wieder einen Rollbalken statt zwei.** Die zwei Kaesten
   (`max-height: calc(100vh - 12rem)`) waren die Antwort darauf, dass eine
   Gliederung nicht mit dem Text nach oben verschwinden darf. Die Leiste loest
   das anders: Sie klebt (`position: sticky`). */
/**
 * **Ein Mass fuer alles, was in dieser Ansicht eine Zeile hoch ist**
 * (08.09.2026): Ausloeser, Blaetterpfeile, Suchfeld - **und die Zeilen in der
 * Klappe**.
 *
 * 2,8 rem ist nicht frei gewaehlt: Es ist die Hoehe, die jedes Eingabefeld im
 * Haus hat (`input[type=text] … { min-height: 2.8rem }`, die Trefferflaeche
 * fuer einen Daumen). Deshalb steht die Zahl hier und nicht an der Leiste -
 * das **Umbenennfeld** in einer Zeile ist genau so ein Eingabefeld, und wenn
 * die Zeile daneben niedriger ist, springt die Liste in dem Moment, in dem man
 * einen Namen aendert.
 *
 * Nachgemessen vor der Aenderung: Feld 44,8 px, Zeile 39,7 px - fuenf Pixel
 * Sprung bei jedem Doppelklick.
 */
.hb { display: block; --hb-hoehe: 2.8rem; }

/* **Die Leiste: Ausloeser, Blaettern, Suche - und sie rollt mit.**

   Sie klebte einen halben Tag lang (`position: sticky; top: var(--navheight)`)
   mit dem Argument, der Weg zur naechsten Seite duerfe nach 3000 Pixeln
   Technik-Text nicht ganz oben liegen. **Am 08.09.2026 verworfen:** Eine
   zweite klebende Leiste unter dem Navigationsblock nimmt auf jedem Bildschirm
   zwei Baender Hoehe weg, dauerhaft, fuer einen Weg, den man beim Lesen selten
   braucht - und wer ihn braucht, ist mit einem Griff oben.

   Wenn das Blaettern spaeter doch dauernd greifbar sein soll, ist die Antwort
   nicht diese Leiste, sondern ein Griff, der wenig Platz kostet. */
.hb-leiste {
  /* Bezugspunkt fuer alles, was sich in der Leiste absolut setzen will. Die
     Klappe braucht ihn nicht - sie haengt an `.hb-klappe`. */
  position: relative;
  /**
   * **Eine Zeile, und darunter zwei - nichts dazwischen** (auf Wunsch).
   *
   * `nowrap` ist hier die Regel und der Umbruch die Ausnahme (in der
   * Mobilregel weiter unten). Mit `wrap` als Vorgabe entstand eine dritte
   * Gestalt: Zwischen den Breiten passten Ausloeser und Blaettern in die erste
   * Zeile und die Suche fiel allein in die zweite - eine Abstufung, die
   * niemand entworfen hat, sondern die aus den drei Grundbreiten herausfiel.
   *
   * Schrumpfen duerfen alle drei (`min-width: 0` an Klappe und Suche), also
   * kostet `nowrap` keine abgeschnittene Zeile - nur der Ausloeser wird
   * knapper, und das ist die richtige Reihenfolge: Er traegt den laengsten
   * Text und ist der einzige, der Kuerzen vertraegt.
   */
  display: flex; flex-wrap: nowrap; align-items: center; gap: .5rem .8rem;
  /**
   * **Genauso hoch wie der Navigationsblock** (08.09.2026, auf Wunsch).
   *
   * `--navheight` ist dessen **gemessene** Hoehe (`chrome.js bindChrome` setzt
   * sie nach dem Aufbau). Damit stimmt die Leiste auch dann noch, wenn dort
   * eine andere Schriftgroesse steht - eine getippte Zahl waere beim naechsten
   * Mal falsch.
   *
   * `min-height` und nicht `height`: Auf dem Telefon bricht die Zeile um, und
   * eine feste Hoehe schnitte das Suchfeld ab.
   */
  min-height: var(--navheight, 3.7rem);
  margin: 0 0 1.4rem; padding: 0;
  background: var(--paper); border-bottom: 1px solid var(--line);
}

/* Der Ausloeser traegt „Bereich › Seite" - die Brotkrume, die die Spalte
   umsonst mitlieferte. Er waechst mit dem Platz, alles andere behaelt seinen. */
/* **Der Ausloeser bekommt doppelt so viel vom freien Platz wie die Suche**
   (08.09.2026). Beide standen auf `flex-grow: 1` und teilten sich den Rest
   gleich - der Ausloeser traegt aber „Bereich › Seitentitel" und die Suche ein
   Wort. Die Klappe erbt die Breite (`width: 100%`), wird also mitbreiter. */
.hb-klappe { position: relative; flex: 2 1 18rem; min-width: 0; }
.hb-ausloeser {
  display: flex; align-items: center; gap: .5rem; cursor: pointer;
  /* Kein senkrechtes Polster - die Hoehe kommt von `--hb-hoehe`, und
     `align-items: center` setzt den Text hinein. Zwei Angaben fuer dieselbe
     Hoehe waeren zwei Stellen, an denen sie sich aendern kann. */
  min-height: var(--hb-hoehe); padding: 0 .6rem;
  border: 1px solid var(--line); background: var(--paper);
  /* The radius of every field and button in the backend (`--feld-radius`). */
  border-radius: var(--feld-radius);
  font-size: .92rem; color: var(--strong); list-style: none;
}
.hb-ausloeser::-webkit-details-marker { display: none; }
.hb-ausloeser:hover { border-color: var(--strong); }
.hb-klappe > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hb-ausloeser-text {
  flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hb-ausloeser .nav-icon, .hb-ausloeser svg { width: 1rem; height: 1rem; flex: none; }
.hb-klappe[open] .hb-ausloeser svg { transform: rotate(180deg); }

/* Die Klappe selbst - schwarzer Rahmen, Papiergrund, kein Schatten, keine
   runde Ecke. (Bis zum 08.09.2026 stand hier „dieselbe Bauart wie
   `.hb-mehr-liste`" - die Liste des „⋯"-Menues, das es nicht mehr gibt.)

   **Einspaltig, und das ist keine Geschmacksfrage:** `sort.js` sucht das
   Ziel eines Zuges allein ueber `clientY`. In zwei Spalten landete ein Zug in
   der rechten Liste in der linken. */
.hb-klappe-inhalt {
  position: absolute; z-index: 5; top: calc(100% + .3rem); left: 0;
  /* **So breit wie der Ausloeser darueber**, nicht schmaler: Eine Klappe, die
     unter ihrem eigenen Knopf endet, sieht aus wie ein zweites Element. `100%`
     rechnet gegen `.hb-klappe`, und das ist genau der Ausloeser. */
  width: 100%; max-height: 70vh; overflow-y: auto;
  display: grid; gap: 1rem;
  padding: .9rem; border: 1px solid var(--strong); background: var(--paper);
}

/* **In der Klappe ist Hoehe knapp** (08.09.2026): fett der Bereich, direkt
   darunter seine Seiten, und zwischen zwei Bereichen eine Zeile Luft statt
   drei. Ausserhalb bleiben die Maße, wie sie sind - `.bk-gruppe` traegt auch
   die Backend-Navigation, und dort steht mehr Platz zur Verfuegung. */
.hb-klappe-inhalt .hb-gliederung { gap: .7rem; }
.hb-klappe-inhalt .bk-gruppe {
  margin: 0 0 .15rem; font-size: .95rem; font-weight: 700;
}

/* **Zeilen trennt eine helle Linie, kein Rand links** (08.09.2026).

   Links stand ein 2 px Strich, der beim offenen Dokument dunkel wurde - also
   gleichzeitig Zierde und Zustandsanzeige. Neben Trennlinien zwischen den
   Zeilen waere er der dritte Strich im Bild. Den Zustand traegt jetzt der
   **Pfeil** am Zeilenanfang.

   Die Linie sitzt an der **Zeile**, nicht am Verweis: Das „⋯" steht daneben
   und gehoert oberhalb desselben Strichs. */
.hb-klappe-inhalt .hb-gruppe a { padding-left: 0; border-left: 0; }
/* **Kein Abstand zwischen den Zeilen** (08.09.2026). `.hb-gruppe ul` hat
   `gap: .1rem` - in der alten Spalte gliederte das eine Liste ohne Striche.
   Mit Trennlinien **und** einer Blende beim Zeigen wurden daraus 1,6 px Weiss
   zwischen dem Strich und der grauen Flaeche darunter: ein heller Spalt, der
   aussah, als sei die Linie zweimal gezeichnet. Die Linie gliedert jetzt, der
   Abstand ist nicht mehr noetig. */
.hb-klappe-inhalt .hb-gruppe ul { gap: 0; }
.hb-klappe-inhalt .hb-zeile,
.hb-treffer .hb-zeile { border-bottom: 1px solid var(--line); }
/* **Die letzte Zeile gibt ihren Strich ab** - darunter steht die Linie, die
   der Knopf ist, und zwei Striche uebereinander sind einer zu viel. Dieselbe
   Regel wie bei den FAQ-Zeilen im Editor (`:has(+ .zeilenlinie)`). */
.hb-klappe-inhalt .hb-zeile:last-child,
.hb-treffer .hb-zeile:last-child { border-bottom: 0; }

/* Der Pfeil am Zeilenanfang: grau, und bei der offenen Seite dunkel. Er ist
   die Anzeige, die vorher der Rand links war. */
/* **Dieselbe Hoehe wie das Umbenennfeld** - siehe `--hb-hoehe` an `.hb`.
   `align-items: center` setzt den Text hinein; das Polster aus der Grundregel
   bleibt fuer den Fall, dass ein langer Titel umbricht - dann waechst die
   Zeile ueber das Mindestmass hinaus und braucht seine Luft. */
.hb-klappe-inhalt .hb-gruppe a,
.hb-treffer .hb-trefferliste a {
  display: flex; align-items: center; gap: .4rem; min-height: var(--hb-hoehe);
  /* **Keine Unterstreichung** (auf Wunsch): Das ist eine Zeile in einer Liste,
     kein Verweis in einem Satz. Dass sie fuehrt, sagen der Pfeil davor und die
     Flaeche beim Zeigen - der Strich sagte es ein drittes Mal und machte aus
     zwoelf Treffern zwoelf unterstrichene Zeilen untereinander. */
  text-decoration: none;
}
/* **Der Pfeil ist schwarz, immer** (08.09.2026, auf Wunsch).

   Er war grau und wurde beim Zeigen dunkel - trug also den Zustand. Das macht
   jetzt die **Flaeche** (siehe unten), und damit ist der Pfeil frei fuer das,
   was er wirklich sagt: Diese Zeile fuehrt dorthin. Bei allen gleich, weil das
   bei allen gleich gilt.

   .9 statt .8 rem, weil `arrow` zu zwei Dritteln aus Linie besteht - die Spitze
   ist der Teil, den man erkennen soll. */
.hb-klappe-inhalt .hb-gruppe a svg,
.hb-treffer .hb-trefferliste a svg {
  width: .9rem; height: .9rem; flex: none; color: var(--strong);
  transition: transform .12s ease;
}
.hb-klappe-inhalt .hb-gruppe a:hover svg,
.hb-treffer .hb-trefferliste a:hover svg { transform: translateX(.15rem); }

/* **Mouseover ist eine Flaeche, keine Farbe am Zeichen.**

   Sie liegt an der **Zeile**, nicht am Verweis: Das „⋯" steht daneben und
   gehoert zu derselben Zeile - eine Blende, die davor endet, teilt die Zeile in
   zwei Haelften, von denen nur eine reagiert.

   Der Einzug (`.5rem` Polster, derselbe Betrag als negativer Rand) laesst die
   Flaeche links und rechts ueber den Text hinausgehen, ohne die Zeile aus der
   Spalte zu schieben. Ohne ihn klebte die Kante der Blende am ersten
   Buchstaben.

   **Die Blende hat den Ton der Trennlinie** (08.09.2026, auf Wunsch) - vorher
   `--shade`, mit der Begruendung „eine Blende ist eine Flaeche, `--line` ist
   der Ton fuer einen Strich". Die Begruendung stimmt fuer eine Flaeche im
   Freien; hier liegt sie in einer Liste, die **Trennlinien** hat, und dann
   schneidet die Linie oberhalb der Zeile mitten durch die Blende. Sichtbar war
   das vor allem im Dunkeln, wo `--line` **heller** ist als `--shade`: ein
   heller Strich quer ueber die Oberkante der Zeile, auf die man gerade zeigt.

   Mit demselben Ton verschwinden beide Striche in der Flaeche - der von oben
   und der eigene darunter -, und die Zeile unter dem Zeiger ist eine
   geschlossene Flaeche statt einer eingerahmten. */
.hb-klappe-inhalt .hb-zeile,
.hb-treffer .hb-zeile {
  margin: 0 -.5rem; padding: 0 .5rem;
  transition: background-color .12s ease;
}
.hb-klappe-inhalt .hb-zeile:hover,
.hb-treffer .hb-zeile:hover { background: var(--line); }
/* **Der Zustand bleibt am Text.** Die offene Seite steht in `--strong`, die
   anderen in `--soft` (Regel weiter oben) - das traegt jetzt allein, wo vorher
   der Pfeil mitgeholfen hat. **Nicht fett**: dieselbe Hausregel wie beim
   aktiven Reiter, der sich durch Strich und Farbe unterscheidet. */

/* Die Linie am Ende einer Seitenliste - dasselbe Bauteil wie im Editor. In der
   Klappe ist sie flacher: 1,5 rem sind dort schon die Hoehe einer Zeile.

   **Und genauso breit wie die Trennlinien darueber** (08.09.2026): Die Zeilen
   greifen mit `margin: 0 -.5rem` einen halben Zentimeter ueber den Text hinaus,
   damit die Blende beim Zeigen nicht am ersten Buchstaben klebt. Die Linie
   stand auf `width: 100%` und endete deshalb zwei Mal .5 rem frueher - eine
   Stufe am Ende jeder Liste, die nichts bedeutet. Derselbe Einzug, dieselbe
   Kante. */
.hb-klappe-inhalt .zeilenlinie {
  /* **`calc`, nicht `auto`.** Mit `width: auto` war die Linie unter einer
     Seitenliste **null Pixel** breit: Ihr einziges Kind ist das absolut
     positionierte Plus, also hat sie keinen Inhalt, an dem eine Breite
     haengen koennte. Die Bereichslinie darunter taeuschte das - sie ist
     Kind eines Rasters und wird von ihm gestreckt. */
  height: 1.1rem; width: calc(100% + 1rem);
  margin-left: -.5rem; margin-right: -.5rem;
}
/* **Die Bereichslinie braucht Abstand** - sie steht direkt unter der
   Seitenlinie des letzten Bereichs, und beide tragen dasselbe Plus. Bei .5 rem
   sahen sie aus wie ein Knopf, der zweimal gezeichnet wurde; bei 1,4 rem ist
   klar, dass die eine die Liste darueber beendet und die andere die
   Gliederung. Ihren Namen sagen sie ohnehin nur im `title`. */
.hb-bereichslinie { margin-top: 1.4rem; }
.hb-klappe-inhalt .hb-intro { margin: 0 0 .3rem; }

/* Blaettern: zwei Quadrate und die Zahl dazwischen. */
.hb-blaettern { display: flex; align-items: center; gap: .3rem; }
/* **`padding: 0` ist hier die halbe Regel** (08.09.2026).
   Ein `<button>` bringt vom Browser ein eigenes Polster mit (in Chrome
   `1px 6px`); `place-items: center` zentriert dann im **Inhaltsbereich**, und
   der sitzt selbst nicht mittig. Nachgemessen: 12,2 px links gegen 3,8 px
   rechts, 9,8 oben gegen 6,2 unten - bei einem 32er Quadrat mit einem 16er
   Zeichen, das 8/8 haben muesste. */
.hb-pfeil {
  display: grid; place-items: center; padding: 0;
  width: var(--hb-hoehe); height: var(--hb-hoehe);
  border: 1px solid var(--line); border-radius: var(--feld-radius);
  background: none; color: var(--ink); cursor: pointer;
}
/* `display: block` nimmt dem SVG die Grundlinie - als Inline-Element haengt es
   sonst an ihr und sitzt ein paar Zehntel zu tief. */
.hb-pfeil svg { width: 1rem; height: 1rem; display: block; }
.hb-pfeil:hover:not(:disabled) { border-color: var(--strong); color: var(--strong); }
.hb-pfeil:disabled { opacity: .35; cursor: default; }
.hb-pfeil:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* **Feste Breite, damit die Pfeile nicht springen.**
   Der Zaehler steht zwischen zwei Knoepfen. Waechst er von „9 von 9" auf
   „10 von 13", wandert der rechte Pfeil mit - und der haeufigste Klick im
   Handbuch ist genau der. 5,75em fassen „99 von 99" (in der Monospace dieser
   Groesse gemessen 5,42em), `tabular-nums` haelt jede Ziffer gleich breit, und
   zentriert steht die Zahl bei einer wie bei zwei Stellen an derselben Stelle.

   **Die Breite haengt an der Schrift.** Drei Stellen („999 von 999") braeuchten
   6,62em; das Buch mit den meisten Seiten liegt weit darunter, und eine Spalte
   fuer einen Fall, den es nicht gibt, ist Leere zwischen zwei Pfeilen. */
.hb-zaehler {
  font-size: .8rem; color: var(--soft); white-space: nowrap;
  min-width: 5.75em; text-align: center; font-variant-numeric: tabular-nums;
}
/* **Die Suche waechst nicht mit** (`flex-grow: 0`, am Umschlag `.hb-suche`).
   Sie traegt ein Wort; der Ausloeser traegt „Bereich > Seitentitel" und
   darunter haengt die Klappe, in der man liest. Aller freie Platz geht deshalb
   dorthin - bei 1130 px sind das rund 90 px mehr fuer die Klappe. Schrumpfen
   darf das Feld weiter: Auf dem Telefon bricht die Leiste um, und dann braucht
   es die Zeile fuer sich. */
.hb-suchfeld { margin: 0; min-width: 0; }
.hb-suchfeld input { width: 100%; min-height: var(--hb-hoehe); }

.hb-gliederung { display: grid; gap: 1.2rem; }
.hb-gruppe ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .1rem; }
/* **Eine Zahl, keine drei** (08.09.2026).
   Die Zeilenhoehe stand dreimal da: `.25rem` hier, `.4rem` fuer Zeigegeraete
   in der Klappe, `.6rem` fuer Fingergeraete weiter unten. Drei Werte fuer
   dieselbe Frage - und der Unterschied zwischen .4 und .6 sind 3 Pixel.
   Jetzt `.6rem` fuer alle: Mit Trennlinien zwischen den Zeilen braucht jede
   Luft **in** ihrem Feld, sonst klebt der Text am Strich darunter, und die
   Hoehe, die ein Daumen braucht, ist auch die, die sich gut liest. */
/* `.hb-trefferliste a` steht ueberall dort mit dabei, wo eine Zeile der
   Gliederung beschrieben wird: **Ein Treffer ist eine Zeile derselben Sorte.**
   Ohne das faellt er aus jeder dieser Regeln heraus - er waere unterstrichen
   (die Grundform eines Verweises), niedriger als die Zeilen darueber und mit
   einem Pfeil in anderer Groesse. Abgeschrieben statt mitgenannt waeren es
   sechs Werte an zwei Stellen. */
.hb-gruppe a,
.hb-trefferliste a,
.abschnitt-liste a {
  display: block; padding: .6rem 0; font-size: .95rem; line-height: 1.35;
  color: var(--soft); text-decoration: none;
}
.hb-gruppe a:hover,
.hb-trefferliste a:hover,
.abschnitt-liste a:hover { color: var(--strong); }
/* Das offene Dokument: dunkler und mit schwarzer Leiste links, **nicht fett**
   (04.09.2026) - dieselbe Form wie in der Bereichsnavigation daneben
   (`.bk-nav nav a`): Ein Zustand, eine Form. Fett bleibt der Ueberschrift
   vorbehalten. Die Leiste steht immer da und ist nur grau, damit der Text beim
   Wechseln nicht springt. */
.hb-gruppe a, .abschnitt-liste a { padding-left: .6rem; border-left: 2px solid var(--line); }
.hb-gruppe a[aria-current="page"],
.abschnitt-liste a[aria-current="page"] {
  color: var(--strong); border-left-color: var(--strong);
}

/* Was der Text ist, steht ueber dem Text: Abschnitt, Umfang, Stand - und ob er
   erst ein Entwurf ist. Bei einer Quelle, aus der Entscheidungen abgeleitet
   werden, ist das keine Fussnote. */
.hb-herkunft {
  margin: 0 0 1.4rem; padding-bottom: .6rem; border-bottom: 1px solid var(--line);
  color: var(--soft); font-size: .82rem;
}
.hb-herkunft code { font-size: .95em; }

/* Der Text selbst - Lesebreite. Beim Schreiben faellt sie weg, siehe unten. */
/* **Der Inhalt laeuft ueber die ganze Breite** (08.09.2026, auf Wunsch).

   Hier stand `max-width: var(--text)` - die Lesespalte, 46 rem. Sie ist im
   Haus die Regel fuer Fliesstext, und das bleibt sie ueberall dort, wo ein
   Gast liest. **Dieser Bereich ist kein Gast**: Es ist die Arbeitsflaeche
   eines einzigen Menschen, der hier Tabellen, Diagramme und Markdown-Bloecke
   nebeneinander braucht - und der Editor hebt die Deckelung ohnehin auf
   (`.hb-text:has(.hb-editor)`). Zwei Breiten in derselben Ansicht, je nachdem
   ob man liest oder schreibt, waren eine Stufe ohne Bedeutung.

   Der Preis ist offen: Bei 1400 px sind das rund 140 Zeichen je Zeile. Wenn
   das beim Lesen stoert, ist die Antwort ein groesserer Deckel (58 rem wie bei
   den Zeiten), nicht die Rueckkehr zu 46. */
.hb-text { line-height: 1.6; }
.hb-text h1 { margin: 0 0 .8rem; }
.hb-text h2 { margin: 2rem 0 .6rem; }
.hb-text h3 { margin: 1.6rem 0 .4rem; }
.hb-text p, .hb-text ul, .hb-text ol { margin: 0 0 1rem; }
.hb-text code {
  background: var(--shade); padding: .1em .35em; font-size: .9em;
}
.hb-text pre {
  background: var(--shade); padding: 1rem; overflow-x: auto; margin: 0 0 1.2rem;
}
.hb-text pre code { background: none; padding: 0; }
.hb-text blockquote {
  margin: 0 0 1.2rem; padding-left: 1rem; border-left: 3px solid var(--line);
  color: var(--soft);
}

/* **Ein Ablauf als Bild** (07.09.2026, `chrome.js diagramme`).

   Dieselbe Entscheidung wie bei den Tabellen zwei Zeilen weiter unten: Ein
   Diagramm ist breiter als eine Zeile Text und **scrollt in seinem eigenen
   Kasten**, statt die Seite quer zu schieben. Es steht mittig darin - ein
   schmales Diagramm links an der Textkante sieht aus, als sei es abgeschnitten.

   Der Rahmen ist derselbe wie beim Codeblock (`--shade`, kein Radius): Beides
   ist ein Einschub, der nicht Fliesstext ist. **Eckig** - das ist die Marke,
   und Mermaid zeichnet seine Knoten von Haus aus mit runden Ecken, also wird
   `rx`/`ry` hier ausdruecklich zurueckgesetzt. Es sind SVG-Geometrieangaben,
   deshalb greift CSS ueberhaupt. */
.hb-text .diagramm {
  margin: 0 0 1.2rem; padding: 1rem; background: var(--shade);
  overflow-x: auto; text-align: center;
}
.hb-text .diagramm svg { max-width: 100%; height: auto; }
.hb-text .diagramm rect { rx: 0; ry: 0; }

/* Ein Diagramm, das nicht zeichnet, bleibt als Text stehen - mit dem Grund
   darunter. Die Warnfarbe traegt der Grund, nicht der Block: Der Text ist in
   Ordnung, nur die Zeile darin nicht. */
.hb-text .diagramm-grund {
  margin: -.8rem 0 1.2rem; font-size: .88rem; color: var(--state-stop-ink);
}
/* Tabellen in der Technik sind breit - sie scrollen im eigenen Kasten und
   schieben nicht die Seite. */
.hb-text table { border-collapse: collapse; width: 100%; margin: 0 0 1.2rem; font-size: .92rem; }
.hb-text th, .hb-text td { border: 1px solid var(--line); padding: .4rem .6rem; text-align: left; }
.hb-text th { background: var(--shade); }
/**
 * **Die Begriffsspalte bekommt einen Boden.**
 *
 * Die Buecher sind voll von Tabellen der Form „Begriff | was dazu gilt". Ohne
 * Boden bekommt die linke Spalte ihre Breite aus dem Inhalt - und weil die
 * rechte Zelle lang ist, drueckt der Browser sie auf das Mindestmass: bei
 * 1130 px Textbreite auf **125 px**. „Von Lokals fuer Lokals" braucht 152 px
 * und stand damit dreizeilig da; ein Begriff, der umbricht, liest sich als
 * zwei Begriffe.
 *
 * **Nur zweispaltige Tabellen** (`:first-child:nth-last-child(2)` heisst:
 * genau zwei Zellen in der Zeile). Wo es Spalten mit Ueberschriften gibt,
 * traegt der Kopf die Breite, und ein Boden waere eine Zahl, die gegen den
 * Inhalt arbeitet.
 *
 * **11 rem am Schirm, 7 rem auf dem Telefon.** Der Boden muss in der Breite
 * mitgehen, sonst frisst er dort die Erklaerung: Bei 350 px Tabelle bleiben
 * neben 11 rem noch 174 px, und die rechte Zelle waechst von 108 auf 155 px.
 *
 * **Kein `min(11rem, 38%)`** - das waere eine Zeile statt zweier Regeln und
 * wirkt hier nicht: In der automatischen Tabellenberechnung haengt die Breite
 * der Zelle an der Tabelle und die Tabelle am Inhalt. Ein Prozentwert ist
 * damit zirkulaer, der Browser laesst ihn fallen, und mit ihm das ganze
 * `min()`. Nachgemessen: die Spalte blieb bei 125 px, obwohl die berechnete
 * `min-width` `min(176px, 38%)` lautete.
 *
 * Laengere Begriffe brechen weiter um, und das ist richtig: Ein halber Satz in
 * der linken Spalte ist kein Begriff mehr.
 */
.hb-text td:first-child:nth-last-child(2),
.hb-text th:first-child:nth-last-child(2) { min-width: 11rem; }
@media (max-width: 46rem) {
  .hb-text td:first-child:nth-last-child(2),
  .hb-text th:first-child:nth-last-child(2) { min-width: 7rem; }
}
.hb-text img { max-width: 100%; height: auto; }

/**
 * ===========================================================================
 * **DIE TREFFER SIND ZEILEN** (08.09.2026) - dieselben wie in der Gliederung
 * ===========================================================================
 *
 * Ein Treffer war ein Block: fetter Titel, darunter bis zu drei graue Zeilen
 * mit der Umgebung der Fundstelle (`.hb-stelle`). Bei acht Treffern waren das
 * zweiunddreissig Zeilen in einer Klappe, in der Hoehe knapp ist - und man las
 * sie nicht: In dieser Liste sucht man eine **Seite**, und die erkennt man am
 * Namen.
 *
 * Jetzt ist es `.hb-zeile`, **nicht etwas, das so aussieht**: Trennstrich,
 * Grund beim Zeigen, Pfeil und Name kommen aus denselben Regeln wie in der
 * Gliederung darueber. Zwei Listen im selben Kasten, die verschieden aussehen,
 * waeren zwei Bedienungen, die man einzeln lernt.
 *
 * **Und sie steht in einer eigenen Schicht**, rechts unter dem Suchfeld - nicht
 * in der Klappe der Gliederung. Die Antwort erscheint dort, wo die Frage steht;
 * und die Gliederung bleibt stehen, statt fuer die Treffer zu weichen und
 * danach neu gezeichnet zu werden.
 * =========================================================================== */
.hb-trefferliste { list-style: none; margin: 0; padding: 0; }
/* Die Marken hinter dem Namen brauchen Luft - im Markup steht keine, weil
   Leerzeichen zwischen Bausteinen sonst mal da sind und mal nicht. */
.hb-trefferliste .hb-woher,
.hb-trefferliste .bk-zahl { margin-left: .4rem; }
/* Sonst nichts: Die Zeile ist `.hb-zeile` und wird oben mitgenannt, wo die
   Gliederungszeile beschrieben ist - Pfeil, Hoehe, Strich, Blende und Umbruch
   kommen von dort. */

/**
 * **Die Trefferschicht: rechts unter dem Suchfeld.**
 *
 * `.hb-suche` ist der Bezugspunkt - der Umschlag um Feld und Schicht. `right:
 * 0` haelt die Schicht an der rechten Kante des Feldes: Sie gehoert zu dem
 * Feld, in das man tippt, und eine Antwort, die am anderen Ende der Zeile
 * erscheint, sucht man erst.
 *
 * **Breiter als das Feld** (`max(100%, 34rem)`): In das Feld tippt man ein
 * Wort, in der Schicht liest man Seitentitel. Nach links ist Platz - die
 * Schicht waechst dorthin, weil sie rechts verankert ist. Der Deckel
 * `calc(100vw - 2rem)` faengt das Telefon ab, wo sie sonst aus dem Bild liefe.
 *
 * **Woher die 34 kommen:** Der laengste Titel im Bestand („Was Maschinen lesen:
 * robots.txt, sitemap.xml, llms.txt", 54 Zeichen) bleibt mit Buchmarke und Zahl
 * ab 33 rem auf **einer** Zeile; bei 32 bricht er um. Ein Titel, der in zwei
 * Zeilen steht, liest sich in einer Liste wie zwei Treffer. Die 34 sind kein
 * Versprechen - ein laengerer Titel bricht weiter um -, sondern die Stelle, an
 * der das Umbrechen die Ausnahme wird statt der Regel.
 *
 * Aussehen wie die Klappe der Gliederung: schwarzer Rahmen, Papiergrund, kein
 * Schatten, keine runde Ecke. Zwei Schichten in derselben Leiste, die
 * verschieden aussehen, waeren zwei Bauteile, die man einzeln lernt.
 */
.hb-suche { position: relative; flex: 0 1 14rem; min-width: 0; }
.hb-treffer {
  position: absolute; z-index: 5; top: calc(100% + .3rem); right: 0;
  width: max(100%, 34rem); max-width: calc(100vw - 2rem);
  max-height: 70vh; overflow-y: auto;
  padding: .9rem; border: 1px solid var(--strong); background: var(--paper);
}
/* Die Zeilen darin sind die der Gliederung - `.hb-treffer` wird deshalb
   ueberall dort mitgenannt, wo `.hb-klappe-inhalt` steht. */
.hb-treffer .count { margin: 0 0 .4rem; }
/* **Auf dem Telefon so breit wie das Feld** - dort bricht die Leiste um, das
   Feld nimmt die ganze Zeile, und die 24 rem waeren breiter als der Schirm.
   `left` **und** `right` statt einer Breite: Damit ist die Schicht genau der
   Umschlag, ohne dass eine Zahl das nachrechnen muss. */
@media (max-width: 46rem) {
  /**
   * **Zwei Zeilen: oben die Auswahl, unten Blaettern und Suche** (auf Wunsch).
   *
   * Der Ausloeser traegt „Bereich › Seitentitel" und braucht die ganze Breite -
   * gekuerzt sagt er nicht mehr, wo man steht. Blaettern und Suche sind dagegen
   * beide schmal: die zwei Pfeile mit Zaehler nehmen, was sie brauchen, das
   * Feld den Rest. Getrennt untereinander waeren es drei Zeilen fuer eine
   * Leiste, und das Feld stuende mit 14 rem in einer halbleeren Reihe.
   *
   * Ohne Auswahl gibt es das Blaettern nicht (`blaetternZeigen`) - dann hat das
   * Feld die zweite Zeile fuer sich, ohne dass eine Regel das nachrechnen muss.
   */
  /* Umgebrochen braucht sie wieder Luft - sonst klebt das Suchfeld am Strich.
     Der Abstand stand bei 34 rem und der Umbruch bei 46: Dazwischen war die
     Leiste zweizeilig **ohne** die Luft, die sie dafuer braucht - eine dritte
     Gestalt, die aus zwei verschiedenen Schwellen herausfiel. Eine Schwelle,
     eine Aenderung. */
  .hb-leiste { flex-wrap: wrap; padding: .4rem 0; }
  .hb-klappe { flex: 1 1 100%; }
  .hb-blaettern { flex: 0 0 auto; }
  .hb-suche { flex: 1 1 auto; }
  .hb-treffer { left: 0; width: auto; max-width: none; }
}

/**
 * **Trefferflaechen fuer den Daumen** (06.09.2026, seit dem 08.09.2026 an der
 * richtigen Frage). Auf dem Schirm sind die Zeilen 24 Pixel hoch und man trifft
 * sie mit dem Zeiger; auf einem Telefon ist das die Groesse, bei der man die
 * Nachbarzeile erwischt.
 *
 * Die Regel hing an `max-width: 60rem` - der Abfrage, die das zweispaltige
 * Raster umschaltete. Das Raster gibt es nicht mehr, und die Frage war ohnehin
 * die falsche: Ein Telefon ist kein schmales Fenster, es ist ein Geraet ohne
 * Zeiger. Ein schmales Fenster auf einem Schirm bekam die grossen Flaechen
 * umsonst, ein Tablet im Querformat gar nicht.
 */
@media (hover: none) {
  /* Das Padding der Zeilen steht jetzt in der Grundregel - hier bleibt nur,
     was ohne Zeiger wirklich anders sein muss: die Flaeche des „⋯". */
  .hb-tun { width: 2.75rem; height: 2.75rem; }
}

/* Auf dem Telefon nimmt das Suchfeld die zweite Zeile und die Klappe die volle
   Breite - eine Regel, keine Medienabfrage: `flex-wrap` und die Grundbreiten
   erledigen es. Hier steht nur, was `flex` nicht kann. */
@media (max-width: 34rem) {
  .hb-suchfeld { flex-basis: 100%; }
  .hb-klappe-inhalt { width: 100%; }
}

/* ==========================================================================
   Die Dokumentation: vier Buecher, ein Editor
   ==========================================================================

   Die Klassen `.hb-*` oben tragen weiter die Gliederung und den Text - vier
   Bereiche benutzen sie, nicht mehr einer. Was hier dazukommt, ist das
   Schreiben: Werkzeug in der linken Spalte, Kopfzeile mit Knoepfen ueber dem
   Text, das Formular an derselben Stelle wie der Text selbst.
   ========================================================================== */

/* Titel und „ändern" in einer Zeile - der Knopf gehoert dem Abschnitt, also
   sitzt er an ihm und nicht in einer eigenen Reihe. */
.hb-gruppe .bk-gruppe {
  display: flex; align-items: baseline; justify-content: space-between; gap: .5rem;
}
.hb-mini {
  border: 0; background: none; padding: 0; font: inherit; font-size: .78rem;
  color: var(--soft); cursor: pointer; text-decoration: underline;
}
.hb-mini:hover, .hb-mini:focus-visible { color: var(--strong); }
/**
 * **Ein Abschnitt ohne Seiten ist der Knopf, der die erste anlegt** (06.09.2026).
 *
 * Hier stand das Wort „leer" - eine Auskunft, die man schon hat, wenn man auf
 * eine leere Liste sieht. Ein leerer Zustand, der den ersten Schritt anbietet,
 * kostet dieselbe Zeile und spart den Weg zum Werkzeug darunter.
 */
/**
 * **Der Einleitungssatz eines Bereichs ist eine Zeile ohne Rahmen.**
 *
 * Er haengt an der Kopfzeile darueber und ist keine Seite - also traegt er
 * weder den Strich einer Zeile noch ihre Mindesthoehe. Ein Satz, der umbricht,
 * darf wachsen; eine Zeile, die auf eine Seite fuehrt, nicht.
 */
.hb-introzeile { list-style: none; border-bottom: 0 !important; }
.hb-introzeile .hb-intro { display: block; }

.hb-leer { list-style: none; font-size: .82rem; padding: .25rem 0 .25rem .6rem; }
.hb-leer .wie-link { font-size: inherit; color: var(--soft); }
.hb-leer .wie-link:hover { color: var(--strong); }
.hb-werkzeug { display: flex; flex-wrap: wrap; gap: .5rem; }
.hb-werkzeug .action { font-size: .82rem; padding: .4rem .6rem; }

/* --------------------------------------------------------------------------
   DIE GLIEDERUNG ALS ARBEITSFLAECHE (06.09.2026)
   -------------------------------------------------------------------------- */

/**
 * **Der Satz ueber der Liste, einmal.** Er sagt, was man hier tun kann -
 * ziehen, `Alt` und Pfeil, Doppelklick. An jeder Zeile stuende er zwanzigmal;
 * als `title` an einem Griff faende ihn niemand, der ihn braucht.
 */
.hb-hinweis { margin: 0; font-size: .78rem; }
.hb-hinweis kbd {
  font: inherit; font-size: .95em; background: var(--shade);
  border: 1px solid var(--line); padding: 0 .25rem;
}
/**
 * **Waisen stehen da, wenn es welche gibt.** `outline` zaehlt sie seit je
 * „damit ein solcher Fall sichtbar waere" - gezeigt hat sie nie jemand. Eine
 * Zahl, die niemand sieht, ist keine Sicherung.
 */
.hb-waisen {
  margin: 0; font-size: .8rem; font-weight: 700; color: var(--state-stop-ink);
}
/** Was in eine Schublade gehoert - genau das, was man beim Ablegen braucht. */
.hb-intro { margin: -.2rem 0 .2rem; font-size: .78rem; color: var(--soft); line-height: 1.4; }

/**
 * **Die Zeile traegt den Verweis und die zwei Zeichen** - nebeneinander, die
 * Zeichen erst beim Zeigen. Zwanzig Zeilen mit dauerhaften Zeichen sind ein
 * Muster, kein Angebot. (Bis zum 08.09.2026 stand hier ein „⋯".)
 */
.hb-zeile { display: flex; align-items: center; gap: .2rem; }
.hb-zeile > a { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.hb-zeile .hb-entwurf { margin-left: .35rem; }
/**
 * ===========================================================================
 * **STIFT UND TONNE IN DER ZEILE** (08.09.2026) - vorher ein „⋯"
 * ===========================================================================
 *
 * Hinter dem Menue lagen bei einer Seite **zwei** Punkte. Ein Menue fuer zwei
 * Dinge ist ein Klick, der nichts entscheidet: Man macht es auf, um zu sehen,
 * dass es zwei sind. Jetzt stehen beide rechts in der Zeile.
 *
 * **Sie erscheinen beim Zeigen** - wie vorher das „⋯", und aus demselben
 * Grund: Zwanzig Zeilen mit je zwei dauerhaften Zeichen waeren vierzig Zeichen
 * und eine Liste, in der man den Namen sucht. Ohne Zeigegeraet stehen sie
 * immer da und sind 2,75 rem gross - ein Daumen trifft kein 24er Feld.
 *
 * **Die Tonne wird beim Zeigen nicht rot.** Rot gehoert im Haus keiner
 * Handlung, sondern der Rubrik „Uebernachten"; die Warnung steht in der
 * Rueckfrage, die danach kommt, nicht in der Farbe davor.
 * =========================================================================== */
.hb-zeilentun { flex: none; display: flex; gap: .1rem; }
.hb-tun {
  display: grid; place-items: center; cursor: pointer;
  width: 1.6rem; height: 1.6rem; padding: 0; border: 0; background: none;
  color: var(--soft); opacity: 0;
}
.hb-tun svg { width: .95rem; height: .95rem; }
.hb-zeile:hover .hb-tun,
.hb-kopfzeile:hover .hb-tun,
.hb-tun:focus-visible { opacity: 1; }
.hb-tun:hover { color: var(--strong); }
.hb-tun:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
/** Auf einem Finger gibt es kein Zeigen - dort stehen sie immer da. */
@media (hover: none) {
  .hb-tun { opacity: 1; width: 2.75rem; height: 2.75rem; }
  .hb-tun svg { width: 1.1rem; height: 1.1rem; }
}

/**
 * **Das Feld beim Umbenennen steht an der Stelle des Namens** - gleiche
 * Schriftgroesse, gleicher Einzug, eckig. Es soll wie der Name aussehen, in
 * den man hineingreift, und nicht wie ein Formular, das aufgeht.
 */
.hb-umbenennen {
  flex: 1; min-width: 0; font: inherit; font-size: .95rem; line-height: 1.35;
  padding: .25rem .3rem; margin-left: .6rem;
  border: 1px solid var(--strong); border-radius: 0;
  background: var(--paper); color: var(--ink);
}
.hb-kopfzeile .hb-umbenennen { margin-left: 0; font-size: inherit; font-weight: inherit; }

/**
 * **Die Einfuegelinie beim Ziehen** - zwei Pixel in der staerksten Tinte, in
 * beiden Modi. Kein schwebendes Abbild, kein Schatten, keine Rundung: Die
 * Linie sagt, wo die Zeile landet, und das ist die ganze Frage.
 */
.sort-linie {
  height: 0; border-top: 2px solid var(--strong); margin: -1px 0;
  list-style: none; pointer-events: none;
}
/** Die gezogene Zeile bleibt stehen und wird blass - sie ist noch ihr Platz. */
.sort-zieht { opacity: .4; }

/* **Der Entwurf traegt die Farbe des Wartens** - dieselbe wie ein Bild in der
   Pruefliste (`--state-wait-*`). Ein eigener Farbwert waere ein zweites
   Vokabular fuer denselben Zustand: noch nicht draussen. */
.hb-entwurf {
  display: inline-block; padding: 0 .3rem; font-size: .7rem; font-weight: 700;
  background: var(--state-wait-bg); color: var(--state-wait-ink);
}
/* Aus welchem Buch ein Treffer kommt. Gesucht wird ueber alle vier, also muss
   am Treffer stehen, wohin er fuehrt. */
/* **Das Herkunftswort ist eine Marke** (auf Wunsch): „Einstiegsseiten",
   „Themen", „Orte" sagen, aus welchem Abschnitt der Treffer kommt - eine
   Einordnung, kein Text. Getragen wird sie von `.konto-status`, der Pille des
   Hauses; hier bleibt, was nur hier gilt: Sie soll nicht mitwachsen und nicht
   umbrechen, wenn der Titel lang wird. */
.hb-woher { flex: none; white-space: nowrap; }

/* ==========================================================================
   DIE MUSTERSEITE - die Bauteile selbst, nebeneinander
   ==========================================================================

   **Der Kasten gibt nur den Rahmen, nie das Aussehen.** Jedes Muster steht in
   seiner eigenen Buehne mit Namen darueber und Begruendung darunter - was
   dazwischen liegt, gestaltet sich aus seinen eigenen Regeln. Eine Zeile hier,
   die ein Muster schoener macht, waere die Luege, wegen der man der Seite
   nicht mehr glauben kann.

   Zwei Spalten ab 60 rem: Die Muster sind schmal, und untereinander waere die
   Seite eine Rolle ohne Uebersicht - und Uebersicht ist der Grund, warum es
   sie gibt. */
.sg-musterkasten {
  display: grid; gap: 1.4rem; margin: 1.2rem 0;
}
@media (min-width: 60rem) {
  .sg-musterkasten { grid-template-columns: 1fr 1fr; }
}
.sg-muster { border: 1px solid var(--line); padding: .9rem 1rem 1rem; }
.sg-muster-kopf {
  display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  margin-bottom: .7rem;
}
.sg-muster-kopf code { font-size: .82rem; }
.sg-muster-wort { font-size: .82rem; color: var(--soft); }
/* Die Buehne traegt Abstand, keinen Grund: Ein grauer Kasten hinter einem
   Bauteil aendert, wie seine Farben wirken - und genau das soll man hier
   beurteilen koennen. */
.sg-muster-buehne { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; }
/* Felder und Tabellen brauchen die ganze Breite, nicht eine Reihe. */
.sg-muster-buehne > .feld,
.sg-muster-buehne > .feld-paar,
.sg-muster-buehne > table,
.sg-muster-buehne > details,
.sg-muster-buehne > .zeilenlinie { width: 100%; }
/**
 * ===========================================================================
 * **DIE KAESTEN STEHEN IN EINEM FLIESSTEXT - UND DER SETZT SEINE ABSAETZE**
 * ===========================================================================
 *
 * `.hb-text p` gibt jedem Absatz `margin: 0 0 1rem`, und das ist **eine Klasse
 * und ein Typ** (0-1-1) gegen die eine Klasse eines Musterhinweises (0-1-0):
 * Der Fliesstext gewinnt, der Abstand nach oben war **null**, und jede Zahl,
 * die hier stand, hat nie gegolten.
 *
 * Deshalb traegt jeder Absatz in diesen Kaesten seinen Elternteil im Waehler.
 * Das ist keine Spezifitaetsschlacht, sondern die Aussage: **Was in einem Kasten
 * steht, folgt dem Kasten und nicht dem Absatzrhythmus der Seite.**
 *
 * Und weil die Regel jetzt wirklich greift, genuegt ein **halber** Zentimeter:
 * Die Buehne darueber traegt selbst 0,6 rem `gap`, und der Hinweis ist ein
 * leiser Satz und keine zweite Ueberschrift.
 */
.sg-muster .sg-muster-hinweis {
  margin: .5rem 0 0; font-size: .86rem; color: var(--soft);
}
.sg-muster-hinweis code { font-size: .95em; }

/* ==========================================================================
   DIE SEITEN DES GUIDE - drei Klassen mehr, und keine vierte
   ==========================================================================

   `#/seiten` benutzt die Schale der Dokumentation (`.hb*`) und die Bauteile des
   Editors (`.ed-block`, `.reiter-leiste`, `.wahlreihe`, `.feld`). Neu ist nur,
   was es dort nicht gibt.
   ========================================================================== */

/**
 * **Die Seitenart als Ebene ueber der Gruppe.**
 *
 * Die Doku hat drei Ebenen (Buch, Bereich, Seite), hier sind es vier
 * (Seitenart, Gruppe, Seite) - und die vierte liegt **oben**, nicht unten:
 * `‹ 2 von 21 ›` heisst „die naechste Seite". Waere die Sprache die Blattebene,
 * blaetterte der Pfeil von „Adresse Camping" nach „Sprachen Camping" - ein Weg,
 * den niemand geht.
 *
 * Sie traegt die Typografie einer **Navigationsueberschrift**, nicht die von
 * `.ed-aufklapp` (das ist eine Erklaerung in einem Formular).
 */
.hb-art > summary {
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: .5rem 0;
  cursor: pointer;
  font-weight: 600;
  border-bottom: 1px solid var(--line);
}
.hb-art > summary::-webkit-details-marker { display: none; }
.hb-art > summary::marker { content: ""; }
.hb-art > summary .reiter-zahl { margin-left: auto; }
/** Der Chevron dreht sich, wie ueberall im Haus, wo sich etwas oeffnet. */
.hb-art > summary svg { transition: transform .15s; }
.hb-art[open] > summary svg { transform: rotate(180deg); }
.hb-art + .hb-art { margin-top: .3rem; }
.hb-seitenliste { list-style: none; margin: 0; padding: 0; }

/**
 * **Die Gruppenzeile ist eine Zeile der Liste.**
 *
 * Sie sitzt als erstes `li` **in** der Liste und benutzt damit dasselbe
 * Kastenmodell wie eine Seitenzeile: der Rahmen am `li`, die Höhe
 * (`--hb-hoehe`) an dem Element darin. Als Absatz daneben war sie mit
 * `box-sizing: border-box` einen Pixel flacher als eine Zeile - und aus einer
 * Liste wurden zwei Rhythmen. Beim Überfliegen von 21 Zeilen zählt genau das.
 *
 * Die Marke bleibt die einer Überschrift (halbfett, `--ink`, kein Pfeil davor):
 * **gleich hoch heißt nicht gleich laut.** Und `margin: 0` ist nötig, weil
 * `.hb-klappe-inhalt .bk-gruppe` einen mitbringt, der in der Zeile nichts
 * mehr zu tun hat.
 */
/**
 * **Dieselbe Regel gilt in beiden Klappen** - unter „Seiten" (`.hb-art`) und in
 * der Doku. Zwei Gliederungen, dieselbe Bauart: Wer die eine anfasst, soll
 * nicht die andere hinter sich herziehen muessen.
 */
.hb-klappe-inhalt .hb-kopfzeile,
.hb-art .hb-kopfzeile {
  display: flex;
  align-items: center;
  min-height: var(--hb-hoehe);
  margin: 0;
  padding: 0;
  width: 100%;
}

/**
 * **Der Mangel ist eine Notiz, kein Zustand.**
 *
 * `.hb-entwurf` ist eine gefuellte Marke und sagt, **was die Seite ist**; der
 * Mangel sagt, **was fehlt** - leise, ohne Kasten, rechts in der Zeile. Zwei
 * Sorten Aussage, zwei Formen. Kein Mangel heisst kein Zeichen: Was in jeder
 * Zeile steht, bringt jemandem bei, die Spalte zu ueberlesen.
 */
.hb-mangel {
  margin-left: auto;
  padding-left: .5rem;
  font-size: .72rem;
  color: var(--soft);
  white-space: nowrap;
}
/** Auf dem Telefon bricht er unter den Namen - der Name ist die Zeile. */
@media (max-width: 30rem) {
  .hb-zeile > a { flex-wrap: wrap; }
  .hb-mangel { margin-left: 1.4rem; padding-left: 0; width: 100%; }
}

/**
 * **Die deutsche Vorlage steht ueber dem Feld**, nicht darunter.
 *
 * `.feld-hint` beantwortet „was ist eine gute Antwort" und steht deshalb unter
 * dem Feld. Hier ist es die **Quelle**, und eine Quelle liest man vorher. Das
 * Kuerzel „DE" ist die Marke davor - ohne sie waere es ein Satz, der aussieht,
 * als gehoere er zum Feld darueber.
 */
.sp-quelle {
  margin: .9rem 0 .2rem;
  font-size: .82rem;
  color: var(--soft);
  overflow-wrap: anywhere;
}
/**
 * **Das `DE` davor ist eine Marke, also ist es rund** - dieselbe Form wie
 * `.konto-status` und aus demselben Grund: **Eine Marke ist nichts, was man
 * anklickt.** Rund unterscheidet sie von jedem eckigen Feld, und in diesem
 * Reiter steht sie unmittelbar ueber einem: erst die deutsche Quelle, darunter
 * das Feld, in das die Uebersetzung kommt. Eckig las sie sich als dessen
 * Beschriftung.
 *
 * Sie zaehlt unter der dokumentierten Ausnahme der Zustandsmarke (Styleguide >
 * Form) - keine neue: dieselbe Sache, dieselbe Form.
 */
.sp-quelle > span:first-child {
  display: inline-block;
  margin-right: .4rem;
  padding: 0 .45rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--ink);
}
/** Die drei Adressen als Liste: Sprache, Feld, ganze Adresse. */
.sp-adressen { list-style: none; margin: .6rem 0; padding: 0; }
.sp-adressen > li {
  display: grid;
  grid-template-columns: 8rem minmax(0, 1fr);
  align-items: center;
  gap: .3rem .6rem;
  padding: .35rem 0;
  border-bottom: 1px solid var(--line);
}
.sp-adressen > li > .sp-quelle { margin: 0; }
.sp-adressen > li > .count { grid-column: 2; font-size: .72rem; }
@media (max-width: 34rem) {
  .sp-adressen > li { grid-template-columns: minmax(0, 1fr); }
  .sp-adressen > li > .count { grid-column: 1; }
}
/** Das Statusfeld sitzt im Kopf der Tafel, rechts neben dem Namen. */
.hb-kopf > .hb-status { margin-left: auto; min-width: 11rem; }
/** „Ansehen" an einer Seite, die es noch nicht gibt: Text mit Grund. */
.hb-weg.is-aus { color: var(--soft); cursor: not-allowed; }

/**
 * **„Löschen" ist ein roter Verweis.**
 *
 * `.wie-link` faerbt in `--strong`, weil ein Verweis-der-kein-Verweis-ist im
 * Haus sonst so leise ist wie der Text um ihn herum. Hier soll er es nicht
 * sein: Es ist die einzige Handlung dieses Bildschirms ohne Rückweg, und die
 * Farbe ist das Einzige, was sie von „Ansehen" daneben unterscheidet.
 *
 * `.hb-gefahr` allein genügt nicht - `.wie-link` steht später im Stylesheet und
 * gewinnt bei gleicher Spezifität. Beide Klassen zusammen sind spezifischer als
 * jede einzelne, also stimmt die Reihenfolge unabhängig davon, wo sie stehen.
 */
.wie-link.hb-gefahr { color: var(--state-stop-ink); }

/**
 * **Der Bruch an der Sprachwahl braucht Luft und Kontrast.**
 *
 * `.reiter-zahl` steht sonst in einer Reiterleiste, wo der Abstand aus dem
 * Innenabstand des Reiters kommt. In `.wahl` klebt er am Namen („English6/6"),
 * und auf der **gewaehlten** Flaeche ist `--soft` auf `--strong` nicht zu
 * lesen: Die Zahl ist der Grund, warum man hier klickt - sie darf nicht die
 * leiseste Stelle des Feldes sein.
 */
.wahl .reiter-zahl { margin-left: .4rem; }
.wahl:has(input:checked) .reiter-zahl { color: inherit; }

/* Die Kopfzeile ueber dem Text: links die Herkunft, rechts die Handlungen. */
.hb-kopf {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: .8rem; margin: 0 0 1.4rem; padding-bottom: .6rem;
  border-bottom: 1px solid var(--line);
}
.hb-kopf .hb-herkunft { margin: 0; padding: 0; border: 0; }
.hb-knoepfe { display: flex; flex-wrap: wrap; gap: .5rem; }
.hb-knoepfe .action { font-size: .82rem; padding: .4rem .6rem; }
/* **Ueber einer Doku-Seite stehen Wege, keine Knoepfe** (08.09.2026).

   Hier lagen vier Kaesten (`.action`) ueber jedem Text. Ein Knopf ist im Haus
   der Abschluss einer Eingabe; diese Zeile schliesst nichts ab, sie bietet
   Wege an - und vier gleich laute Kaesten ueber jedem Absatz liest man nach
   dem dritten Mal nicht mehr, man sucht darin.

   `.linklike` traegt die Gestalt (Unterstrich, `--accent`), hier kommt dazu,
   was eine **Reihe** davon braucht. */
.hb-wege {
  display: flex; flex-wrap: wrap; align-items: center;
  /* Weiter auseinander als die Knopfreihe (dort .5rem): Kaesten trennen sich
     durch ihren Rahmen, unterstrichene Woerter nur durch Luft. */
  gap: .3rem 1.1rem;
  font-size: .82rem;
}
/* **Auf dem Telefon ist ein Wort ohne Flaeche ein Zielproblem.** Dieselbe Zahl
   wie an der Zeilenlinie im Editor: 44 px sind die Kante, die ein Daumen
   trifft. Am Schirm bleibt es die Zeile, die es ist - dort zielt ein Zeiger. */
@media (hover: none) {
  .hb-weg { min-height: 2.75rem; }
}
.hb-weg:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* **Der Statusweg traegt sein Gewicht in der Schrift**, nicht im Rahmen.
   „Freigeben" ist die folgenreichste Handlung dieser Seite - und trotzdem
   derselbe Weg wie die anderen: Eine Stelle kann nicht je nach Zustand die
   Bauform wechseln. */
.hb-weg-stark { font-weight: 600; }

/* **Loeschen sieht nicht wie die anderen aus.** Kein rotes Feld - die Marke hat
   keine Warnfarbe -, aber die Tinte des abgelehnten Zustands: erkennbar anders,
   ohne zu schreien.

   **Zwei Gestalten, eine Bedeutung:** In der Wegzeile ueber einer Doku-Seite
   ist es ein Wort, beim Abschnitt (`abschnitt-loeschen`) weiterhin ein Kasten -
   dort steht es zwischen anderen Kaesten. Die Tinte ist beide Male dieselbe. */
.hb-gefahr { color: var(--state-stop-ink); }
/* **Rechts abgesetzt** - in der Knopfreihe des Bereichs-Editors steht links
   „Speichern" und „Abbrechen", und die schliessen die Eingabe ab. Loeschen
   schliesst nichts ab, es raeumt weg. Zwischen zwei gleich grossen Kaesten sah
   es aus wie eine dritte Art zu speichern. Dieselbe Entscheidung wie beim
   Entfernen einer Bildzeile im Editor. */
.hb-weg-rechts { margin-left: auto; }
.action.hb-gefahr { border-color: var(--state-stop-ink); }
.action.hb-gefahr:hover, .action.hb-gefahr:focus-visible {
  background: var(--state-stop-ink); color: var(--paper);
}
.linklike.hb-gefahr:focus-visible { outline-color: var(--state-stop-ink); }

/* --------------------------------------------------------------------------
   Der Editor
   -------------------------------------------------------------------------- */

/* **Beim Schreiben faellt die Lesebreite weg.** `.hb-text` haelt 46rem, damit
   ein Text lesbar bleibt; ein Eingabefeld in derselben Breite waere ein
   Guckloch. `:has()` statt einer zweiten Klasse am Behaelter: Der Zustand
   „hier steht ein Formular" steckt schon im Inhalt. */
/* Die Regel `.hb-text:has(.hb-editor) { max-width: none }` ist am 08.09.2026
   weggefallen: Der Text hat keinen Deckel mehr, also gibt es nichts
   aufzuheben. */
.hb-editor { display: grid; gap: 1rem; }
.hb-editor-reihe {
  display: grid; gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
}
/* Markdown ist Code, solange man es schreibt: gleiche Zeichenbreite, damit
   Tabellen und Listen im Feld stehen wie im Text. */
.hb-editor textarea[name="body"] {
  font-family: var(--mono);
  font-size: .88rem; line-height: 1.55; min-height: 24rem;
}
.hb-editor .konto-notiz { margin: -.4rem 0 0; }

/* Die Liste der Staende - dieselbe Zeile wie in der Pruefliste. */
/**
 * **Die Staende als Tabelle, eine Zeile je Stand** (08.09.2026).
 *
 * Vorher eine Liste aus Kaesten - vier Zeilen Hoehe je Stand, und nach zehn
 * Speicherungen scrollte man durch neunzig Zeilen, um zwei Zeitpunkte zu
 * vergleichen. Eine Versionsliste liest man **quer**; dafuer gibt es Spalten.
 *
 * Die Grundform kommt aus `.hb-text table` - dieselbe Tabelle, die eine
 * Doku-Seite selbst benutzt. Kein zweites Aussehen fuer dieselbe Sache.
 */
.hb-staende {
  border-collapse: collapse; width: 100%; margin: 0 0 1.2rem; font-size: .92rem;
}
.hb-staende th, .hb-staende td {
  border: 1px solid var(--line); padding: .4rem .6rem; text-align: left;
  vertical-align: top;
}
.hb-staende th { background: var(--shade); }
/* Der Zeitpunkt bricht nicht um - er ist der Schluessel der Zeile. */
.hb-staende td:first-child { white-space: nowrap; }
/* Zahlen rechts: Man vergleicht sie untereinander, nicht mit dem Text daneben. */
.hb-staende .hb-staende-zahl { text-align: right; white-space: nowrap; }
/* Die zwei Wege nebeneinander, mit einem Abstand, der sie trennt, ohne die
   Zeile zu dehnen. `nowrap`, damit „Zurueckholen" nicht in zwei Zeilen faellt
   und die Zeile hoeher macht als alle anderen. */
.hb-staende .hb-staende-tun {
  white-space: nowrap; width: 1%; text-align: right;
}
.hb-staende .hb-staende-tun .wie-link + .wie-link { margin-left: .9rem; }
/**
 * **Der alte Titel, wenn es einen gibt.** Er steht unter dem Zeitpunkt und
 * nicht in einer eigenen Spalte: Bei den meisten Staenden gibt es ihn nicht,
 * und eine Spalte, die neunmal leer ist, ist eine Spalte zu viel.
 */
.hb-staende-titel { display: block; font-size: .85em; color: var(--soft); }

/* Die Bilanz der Anker im Hilfebereich ist am 08.09.2026 weggefallen - mit ihr
   `.hb-stand`. Der Grund steht in `web/profil.js` bei `buchMarkup`: Die anderen
   drei Buecher hatten keinen solchen Kasten, und der Riegel gegen ein
   Fragezeichen ohne Text sitzt in `web/hilfe.js`, nicht in einer Zahl. */

/* --------------------------------------------------------------------------
   Der Farbkasten des Styleguide

   **Er steht im Text, nicht ueber der Gliederung** (08.09.2026). Vorher hing er
   am Bereichskopf und damit ueber **jeder** Seite des Buchs - auch ueber „Der
   Ton" und „Das Logo". Jetzt setzt ihn die Seite „Die Farben" selbst, ueber
   einen Block ```farben (siehe `farbkaesten()` in `profil.js`).

   Damit braucht er oben denselben Abstand wie unten: Er ist ein Absatz zwischen
   Absaetzen und nicht mehr der Deckel einer Ansicht. Die Linie bleibt - sie
   trennt ihn vom Text darunter, wie eine Abbildung von ihrer Umgebung.
   -------------------------------------------------------------------------- */

.sg-farbkasten {
  margin: 1.6rem 0 1.8rem; padding: 1.2rem 0;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
/* Die eigene Ueberschrift steht enger als eine des Textes: Sie gehoert zum
   Kasten und nicht zur Gliederung der Seite. */
.hb-text .sg-farbkasten > h2 { margin: 0 0 .3rem; font-size: 1.05rem; }
.sg-farbkasten > p { margin: 0 0 1.2rem; }
.sg-gruppe { margin: 0 0 1.2rem; }
.sg-farben {
  list-style: none; margin: .4rem 0 0; padding: 0;
  display: grid; gap: .8rem; grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
}
.sg-farben li { display: grid; gap: .15rem; font-size: .78rem; }
/* Das Feld traegt einen Strich in Tinte, sonst verschwindet Weiss auf Weiss -
   und genau Weiss ist eine der Farben, die hier stehen. */
.sg-feld {
  display: block; height: 2.6rem; border: 1px solid var(--line);
}
.sg-farben code { font-size: .9em; }
.sg-farben small { color: var(--soft); }

/* --------------------------------------------------------------------------
   Zeichen und Logos im Styleguide - gezeigt, nicht aufgezaehlt (08.09.2026)

   Dieselbe Bauart wie der Farbkasten: offener Abschnitt zwischen zwei Linien,
   eigene Ueberschrift, ein Satz zur Herkunft, darunter Gruppen.

   **Ein Zeichen steht in einem Feld, nicht frei.** Ein 17er Glyph zwischen
   Textzeilen ist ein Fussel; das Feld gibt ihm eine Groesse, in der man die
   Strichstaerke wirklich vergleichen kann - und darum geht es hier.
   -------------------------------------------------------------------------- */

.sg-kasten {
  margin: 1.6rem 0 1.8rem; padding: 1.2rem 0;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.hb-text .sg-kasten > h2 { margin: 0 0 .3rem; font-size: 1.05rem; }
.sg-kasten > p { margin: 0 0 1.2rem; }

.sg-zeichen {
  list-style: none; margin: .4rem 0 0; padding: 0;
  display: grid; gap: .8rem; grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
}
.sg-zeichen li { display: grid; gap: .35rem; justify-items: center; text-align: center; }
.sg-zeichenfeld {
  display: grid; place-items: center; width: 100%; height: 3.4rem;
  background: var(--shade); color: var(--strong);
}
/* Alle Saetze auf dieselbe Kantenlaenge - sie haben drei Koordinatenfelder
   (17, 24, 32), und nebeneinander soll man die Zeichnung vergleichen, nicht die
   Rechnung dahinter. */
.sg-zeichenfeld svg, .sg-zeichenfeld .sg-glyph { width: 1.6rem; height: 1.6rem; }
.sg-zeichen code { font-size: .75rem; color: var(--soft); }
.sg-zeichenwort { font-size: .8rem; font-weight: 700; }

/**
 * **Die Kategoriezeichen stehen groesser** (08.09.2026).
 *
 * Sie sind die sechs, die auf jeder Kachel, in jeder Navigation und auf jeder
 * Karte stehen - und die einzigen, die eine eigene Farbe tragen. In der Reihe
 * der Hüllenzeichen waeren sie dreissig gleich grosse Quadrate; hier sind es
 * sechs, und sie duerfen den Platz nehmen, den ihre Bedeutung hat. Groesser
 * heisst hier auch: Man sieht, ob der Strich stimmt. Genau dafuer gibt es
 * diesen Kasten.
 */
.sg-gruppe:has(.sg-zeichenwort) .sg-zeichen {
  grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr));
}
.sg-gruppe:has(.sg-zeichenwort) .sg-zeichenfeld { height: 7.5rem; }
.sg-gruppe:has(.sg-zeichenwort) .sg-zeichenfeld svg { width: 4.2rem; height: 4.2rem; }

/**
 * **Die Zeile richtet sich am Bild aus, nicht am laengsten Dateinamen.**
 *
 * `align-content: start` und eine **feste** Feldhoehe: Mit `min-height` war
 * jedes Feld so hoch wie sein Bild, und damit standen in einer Zeile fuenf
 * Wortmarken auf fuenf verschiedenen Hoehen. Die Kacheln vergleicht man
 * nebeneinander - dann muessen sie auf einer Linie liegen.
 *
 * **14 rem und nicht 11**: Eine Kachel traegt zwei Haelften, also bekommt ein
 * Logo die halbe Spalte. Die breiten (Logo, Label) waren bei 11 rem 5,5 rem
 * breit und damit kleiner als das Wort darunter.
 */
.sg-marken {
  list-style: none; margin: .4rem 0 0; padding: 0;
  display: grid; gap: 1.1rem; align-items: start;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
}
.sg-marke { display: grid; gap: .3rem; align-content: start; }
/**
 * **Die Box ist doppelt so hoch wie das Logo darin** (10,8 gegen 5,4 rem).
 *
 * Ein Logo braucht Luft, und die Luft **gehoert zur Marke**: Die Wortmarke ist
 * breit und flach, das Patch rund - in einer knappen Box sitzt das eine
 * gequetscht und das andere randlos, und man beurteilt dann den Zuschnitt statt
 * das Zeichen. Auf 10,8 rem steht jedes der beiden frei, und das Patch ist
 * gross genug, dass man den Strich darin sieht - der Punkt, wegen dem die Datei
 * hier ueberhaupt steht.
 *
 * **Dieselbe Hoehe fuer alle**, damit die Reihe eine Kante hat: Ein Raster, in
 * dem jede Kachel so hoch ist wie ihr Inhalt, ist eine Treppe.
 */
.sg-marke-feld { display: grid; place-items: center; padding: 1.6rem 1.1rem; height: 10.8rem; }
.sg-marke-feld img { max-width: 100%; max-height: 5.4rem; grid-area: 1 / 1; }

/**
 * **Der Grund und die Fassung sind eine Entscheidung, also ein Schalter.**
 *
 * Beide Bilder stehen im Dokument und liegen uebereinander (`grid-area: 1/1`);
 * sichtbar ist das, was zum Grund gehoert. Kein Neubau beim Umschalten - und
 * damit kein Nachladen und kein Flackern.
 *
 * **Feste Werte, mit Grund** - wie beim Bildnachweis auf dem Foto: Die Dateien
 * sind schwarz und weiss gezeichnet, also braucht die eine Weiss und die andere
 * Schwarz. `--paper` waere im Dunkelmodus ein dunkler Grund unter einem
 * schwarzen Logo.
 */
.sg-grundwahl { margin: 0 0 1.2rem; }
.sg-logos[data-grund="hell"] .sg-marke-feld { background: #ffffff; }
.sg-logos[data-grund="dunkel"] .sg-marke-feld { background: #12161a; }
.sg-logos[data-grund="hell"] .auf-dunkel,
.sg-logos[data-grund="dunkel"] .auf-hell { display: none; }

/**
 * **Ein einfarbiges Zeichen ohne zweite Fassung liegt als Maske.** Das Signet
 * gibt es nur schwarz gezeichnet; als Bild waere es auf dunklem Grund nicht da.
 * Die Datei traegt hier nicht das Bild, sondern seine **Deckung** - der
 * Alphakanal stanzt eine Flaeche in der Tinte des Grundes aus. Dieselbe
 * Mechanik wie das Querzeichen in der Huelle und wie die Skizzen: eine Datei,
 * jeder Grund.
 *
 * `currentColor` und nicht `--strong`: Die Tinte gehoert hier dem **Kasten**,
 * nicht der Seite - auf dunklem Grund ist sie weiss, auch wenn die Seite hell
 * steht.
 */
.sg-logos[data-grund="hell"] .sg-marke-feld { color: #000000; }
.sg-logos[data-grund="dunkel"] .sg-marke-feld { color: #ffffff; }
.sg-maske {
  grid-area: 1 / 1; width: 100%; height: 3.6rem; background: currentColor;
  -webkit-mask: var(--maske) center / contain no-repeat;
  mask: var(--maske) center / contain no-repeat;
}
/* Derselbe Griff wie beim Musterhinweis: `.hb-text p` schlaegt eine einzelne
   Klasse, also steht der Elternteil davor. Ohne ihn hing unter jedem Markenwort
   ein Zentimeter Luft, den niemand gesetzt hat. */
.sg-marke .sg-marke-wort { margin: .1rem 0 0; font-weight: 700; font-size: .85rem; }
/**
 * **Der Dateiname und der Weg zu ihm stehen in einer Zeile.**
 *
 * Das Zeichen sitzt am **Anfang der letzten Zeile** und nicht am oberen Rand
 * der Kachel: Oben liegt das Logo, und alles, was daraufliegt, verdeckt es -
 * gerade bei den kleinen Zeichen waere ein Knopf in der Ecke ein Teil der
 * Marke. Unten gehoert es zu dem, was es holt: dem Namen daneben.
 *
 * `align-items: start`, weil ein langer Name umbricht - das Zeichen bleibt
 * dann an der ersten Zeile stehen und wandert nicht in die Mitte.
 */
.sg-marke .sg-marke-datei {
  margin: 0; display: flex; gap: .4rem; align-items: start;
}
.sg-marke code { font-size: .72rem; color: var(--soft); word-break: break-all; }
.sg-laden {
  flex: none; display: grid; place-items: center; width: 1.5rem; height: 1.5rem;
  margin-top: -.15rem; color: var(--soft); text-decoration: none;
}
.sg-laden:hover, .sg-laden:focus-visible { color: var(--strong); }
.sg-laden svg { width: .95rem; height: .95rem; }
/* Auf dem Telefon gibt es kein Zeigen, und ein 24px-Ziel trifft kein Daumen. */
@media (hover: none) {
  .sg-laden { width: 2.75rem; height: 2.75rem; margin: -.6rem 0; }
}

/* --------------------------------------------------------------------------
   Das Zeichen der Hilfe und ihr Layer
   -------------------------------------------------------------------------- */

/* **Ein Glyph, kein Knopf mit Grund.** Das Fragezeichen sitzt hinter einer
   Ueberschrift oder einer Beschriftung; ein gefuelltes Feld daneben waere eine
   zweite Handlung in einer Zeile, die schon eine hat. Und es ist ausdruecklich
   nicht das ⓘ - das gehoert dem Bildnachweis. */
/**
 * **Das Hilfezeichen als kleine Pille** (05.09.2026).
 *
 * Es stand in `1.05em` - und `em` neben einer Ueberschrift heisst: so gross wie
 * die Ueberschrift. Neben „Konten" in 2 rem war das ein Buch von 32 Pixeln, das
 * lauter rief als der Titel. Jetzt ein **festes Mass** (14 Pixel) in einer
 * Flaeche von 1,5 rem: Es gehoert zur Zeile, statt sie mitzutragen.
 *
 * Die Flaeche ist die zweite bewusste Rundung im Backend (nach dem
 * Vorschaubild): Ein Zeichen ohne Flaeche neben einer Ueberschrift sieht aus
 * wie ein Satzzeichen; mit Flaeche sieht es aus wie ein Knopf - und einer ist
 * es ja.
 *
 * **Vier Pixel, nicht acht** (05.09.2026): Bei acht war es auf 24 Pixeln fast
 * eine Kapsel und fiel aus der Reihe - Vorschaubild und Kurve daneben stehen
 * auf vier. Wenn `border-radius: 0` schon eine Ausnahme bekommt, dann eine,
 * und nicht zwei verschiedene.
 */
.hilfe-zeichen {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.5rem; height: 1.5rem; flex: none;
  /* Ein grauer Rahmen macht aus der Flaeche einen Knopf: Ohne ihn schwamm die
     Pille im Text, weil ihr Grund fast so hell ist wie das Papier. */
  padding: 0; border: 1px solid var(--line); border-radius: 4px;
  background: var(--shade); color: var(--soft); cursor: pointer;
  vertical-align: .12em; margin-left: .45rem;
}
.hilfe-zeichen svg { display: block; width: 14px; height: 14px; }
.hilfe-zeichen:hover, .hilfe-zeichen:focus-visible {
  background: var(--strong); border-color: var(--strong); color: var(--paper);
}
.hilfe-zeichen:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }

/* Der Layer: ein Kasten in der Mitte, kein Vollbild. Eine Hilfe haelt kurz an
   und sagt einen Absatz - sie uebernimmt nicht die Seite. */
/**
 * **Die Hilfe benutzt die Schicht der Huelle** (05.09.2026) - Rahmen, Grund
 * und das Kreuz oben rechts stehen dort. Hier bleibt, was diese Schicht
 * unterscheidet: ihre Breite und der Satz ihres Textes.
 *
 * Sie ist schmaler als eine Mail (34 statt 56 rem): Eine Hilfe haelt kurz an
 * und sagt einen Absatz - sie uebernimmt nicht die Seite.
 */
/* 44 statt 34 rem (05.09.2026): Ein Hilfetext hat Tabellen und Aufzaehlungen -
   in 34 rem stand jede Zeile zweimal um. Breiter als die Lesebreite ist er
   trotzdem nicht: Er soll die Seite nicht uebernehmen. */
/* Zwei Klassen, weil `.schicht` weiter unten steht und sonst mit ihren 34 rem
   gewinnt - gleiche Spezifitaet, spaetere Regel. */
.schicht.hilfeschicht { width: min(44rem, calc(100vw - 2rem)); }
/* ---------------------------------------------------------------------------
   **DERSELBE TEXT, DIESELBE KLASSE**

   Es ist **dieselbe Seite** wie unter Dokumentation - dieselbe Zeile im
   Bestand, derselbe Zeichner (`marked.parse`). Also traegt sie im Layer auch
   dieselbe Klasse: `.hb-text`.

   Hier stand ein eigener Satz Regeln, und er war die halbe Miete: Absaetze,
   Aufzaehlungen, `code` und `h3` - aber **keine Tabellen**, kein Codeblock,
   kein Zitat. Eine Hilfeseite mit einer Tabelle stand im Layer ohne Rahmen und
   ohne Kopfzeile da, waehrend dieselbe Seite unter Dokumentation eine Tabelle
   war. Zwei Formatierungen fuer einen Text sind eine zu viel, und die zweite
   ist immer die, an der etwas fehlt.

   Was hier bleibt, ist genau das, was der **Ort** verlangt und nicht der
   Text. */
.hilfe-text > :first-child { margin-top: 0; }
.nav-konto-text {
  flex: 1; min-width: 0; display: grid; gap: .1rem;
  font-size: 1.05rem; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* „Mein Profil" unter dem Namen: Der Name sagt, wer man ist, die Zeile
   darunter, wohin es geht. Zwei Angaben, eine Zeile - deshalb die kleinere. */
.nav-konto-text small { font-size: .82rem; opacity: .7; }
/**
 * **Nur der Pfeil bewegt sich** - deshalb das `>`.
 *
 * Das Konto-Zeichen im Kreis traegt dieselbe Klasse `.nav-icon`, weil es aus
 * demselben Helfer kommt. Ohne den direkten Nachfahren rutschte es beim
 * Ueberfahren mit heraus: Der Pfeil zeigt, wohin die Zeile fuehrt, das Zeichen
 * sagt nur, wessen Zeile es ist - und was nichts ankuendigt, soll sich nicht
 * bewegen.
 */
.nav-konto-zeile > .nav-icon {
  width: 1.15rem; height: 1.15rem; flex: none; transition: transform .18s;
  /* Dieselbe Luft wie an den grossen Zeilen - sie stehen untereinander. */
  margin-right: .5rem;
}
.nav-konto-zeile:hover > .nav-icon { transform: translateX(.2rem); }
.nav-konto-zeile:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: 2px; }
/* Feiner Strich: Das Zeichen steht neben einer Zeile in normaler Strichstaerke
   und soll sie nicht uebertoenen. `vector-effect` haelt den Strich unabhaengig
   von der Skalierung - sonst wird er mit der Groesse mitgezogen. */
/* Groesser als die Schrift daneben, aber feiner gezeichnet: Das Zeichen traegt
   die Rubrik, der Strich soll die Zeile nicht uebertoenen.

   Der Abstand nach rechts sitzt am Zeichen, nicht am Reihenabstand: Der gilt
   auch fuer den Pfeil am anderen Ende, und der soll nicht mitwandern. Lucide
   zeichnet in einem 24er Feld mit Luft am Rand - bei knapp 30 Pixeln Kasten
   sieht dieselbe Luecke schmaler aus als bei 20, deshalb kommt sie in Zahlen
   dazu und nicht nach Gefuehl. */
.nav-row .nav-group-icon {
  /* **Groesser als die Zeile daneben, in jeder Breite.** Das Wort steht in
     `clamp(1.25rem, 3.6vw, 1.6rem)`; bei 1,6 rem waere das Zeichen am weiten
     Schirm genau so gross wie die Schrift und damit nicht mehr die Marke der
     Zeile, sondern ihr Nachbar. 2,5 rem liegt in jeder Breite deutlich
     darueber - gut anderthalbmal das groesste Wort - und macht das
     Zeichen zu dem, was man in der Zeile zuerst sieht. Unter 1,5 verliert es
     gegen die grosse Zeile.

     **Groesse ohne Gewicht: der Strich geht mit herunter.** Hier gilt kein
     `non-scaling-stroke` (das steht nur an der Karte), also rechnet der Browser
     die Strichbreite mit der Groesse hoch. **Deshalb steht der Strich nicht
     hier, sondern als Argument am Zeichen** (`NAV_STRICH` in `chrome.js`): Die
     Marken tragen ihre Staerke gegengerechnet im Pfad, und eine CSS-Angabe am
     `svg` erreicht die gar nicht - sie gilt nur fuer Formen ohne eigene.
     Gerechnet: `1,0 x 28 / 40` = 0,70, also wieder 1,17 px echte
     Strichbreite (bei 2,5 rem, 40 px). Der Wert hier bleibt derselbe, damit beides dasselbe sagt.

     Der Abstand nach rechts sitzt am Zeichen und nicht am Reihenabstand, damit
     der Pfeil am anderen Ende nicht mitwandert. */
  width: 2.5rem; height: 2.5rem; stroke-width: .7; margin-right: .5rem;
}

/* Der Weg zurueck traegt den Pfeil **vor** dem Wort und nach links: Zeichen und
   Richtung sagen dasselbe. */
.nav-back .nav-icon { order: -1; }
.nav-back:hover .nav-icon { transform: translateX(-.2rem); }
/* **Die einzige Linie in Ebene 1 gehoert dem Weg zurueck** - sie trennt die
   Rubrik von ihren Gattungen. Die Rubriken untereinander brauchen keine: Sie
   stehen gross und einzeln, und vier Linien zwischen fuenf Zeilen machten aus
   einer Ordnung eine Tabelle. */
.nav-back {
  margin-bottom: .4rem; padding-bottom: .9rem;
  border-bottom: 1px solid color-mix(in srgb, var(--nav-ink) 22%, transparent);
}

/* **Ebene 2: hellgrau, beim Zeigen weiss - und ohne Pfeil.** Diese Zeilen
   oeffnen nichts, sie fuehren auf eine Seite. Der Pfeil bleibt den Zeilen
   vorbehalten, die eine Ebene aufmachen; sonst hiesse er nur noch "hier kann
   man klicken", und das steht ohnehin an jeder Zeile. */
/* **Ohne Trennlinien.** Die eine Linie oben, unter der Kategorie
   (`.nav-back`), sagt etwas: Darueber steht, wo man ist, darunter, wohin man
   kann. Eine Linie zwischen zwei Gattungen sagt nichts - sie trennt Dinge, die
   zusammengehoeren, und macht aus einer Liste eine Tabelle. Der Abstand
   gliedert schon. */
.nav-level-2 a {
  display: flex; align-items: center; gap: .8rem;
  padding: .75rem 0; font-size: 1.2rem; text-decoration: none;
  color: color-mix(in srgb, var(--nav-ink) 62%, transparent);
}
/* **Eine Zeile bleibt eine Zeile.**

   Die Gattungen sind kurz („Ferienwohnung"), die Titel der **Beitraege** nicht:
   „Schwarzwald Marie und Hannes kaufen – Playmobil 71927 ist da" lief auf drei
   Zeilen um, und zehn Beitraege darunter waren eine Textwand statt einer Liste.

   Gekuerzt statt umgebrochen: In einer Navigation zaehlt, **wie viele** Wege es
   gibt und wie sie anfangen - der Anfang eines Titels unterscheidet ihn, das
   Ende beschreibt ihn. Wer den ganzen Titel will, klickt.

   `min-width: 0` am Flex-Kind ist Pflicht: Ohne es rechnet ein Flex-Element mit
   seiner Inhaltsbreite, und `text-overflow` bekommt nie zu wenig Platz. */
.nav-level-2 a > span {
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.nav-level-2 a:hover, .nav-level-2 a:focus-visible { color: var(--nav-ink); }

/* **Die Sammelzeile ist das Dach, nicht eine Zeile unter Gleichen.**

   „Alles in Uebernachten", „Alle Beitraege" - sie fuehrt auf die Flaeche, die
   *alles* zeigt, waehrend die Zeilen darunter je einen Ausschnitt nehmen. Also
   steht sie **weiss und unterstrichen**, wo die Gattungen hellgrau stehen: Der
   Rang ist ein Unterschied im Ton und in der Linie, nicht in der Schriftstaerke
   (Fett bliebe im Haus dem Gewaehlten vorbehalten).

   **Beim Zeigen faellt der Strich weg, statt zu kommen.** Eine Zeile, die schon
   unterstrichen ist, kann beim Zeigen nichts hinzufuegen - der Unterschied waere
   keiner. So aendert sich hier wie an jeder anderen Zeile *etwas*, und die
   Richtung ist die einzige, die noch frei war.

   `text-decoration` und nicht `border-bottom`: Der Strich soll dem **Wort**
   folgen und nicht der Zeile, die auf die ganze Breite geht. */
.nav-level-2 a.nav-alle {
  color: var(--nav-ink);
  text-decoration: underline;
  text-underline-offset: .22em;
}
.nav-level-2 a.nav-alle:hover,
.nav-level-2 a.nav-alle:focus-visible {
  text-decoration: none;
}
/* Eine Gattung ohne Eintrag bleibt sichtbar und ohne Weg - der Bestand soll
   sich nicht groesser zeigen, als er ist. */
.nav-level-2 .empty {
  padding: .75rem 0; font-size: 1.2rem;
  color: color-mix(in srgb, var(--nav-ink) 28%, transparent);
}


/* Der Umschalter fuer die Darstellung: drei Stellungen, die gewaehlte gefuellt.
   Kein Schieber und kein Sonnen-Mond-Zeichen - "System" laesst sich damit nicht
   ausdruecken, und genau das ist die Voreinstellung. */
.nav-theme { display: inline-flex; border: 1px solid color-mix(in srgb, var(--nav-ink) 40%, transparent); }
.nav-theme button {
  font: inherit; font-size: .82rem; padding: .3rem .6rem; cursor: pointer;
  background: none; border: 0; color: color-mix(in srgb, var(--nav-ink) 75%, transparent);
}
.nav-theme button + button { border-left: 1px solid color-mix(in srgb, var(--nav-ink) 25%, transparent); }
.nav-theme button:hover { color: var(--nav-ink); }
.nav-theme button[aria-pressed="true"] { background: var(--nav-ink); color: var(--nav); }
.nav-theme button:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: -2px; }

@media (prefers-reduced-motion: reduce) {
  /* `.nav-drill` und `.nav-level` seit dem 07.09.2026 dabei: Seit beide Ebenen
     im Dokument stehen, bewegt sich der Streifen wirklich (`transform`) und die
     Sichtbarkeit haengt an einem Uebergang. Ohne diese Zeile bliebe genau die
     grosse Bewegung uebrig, die hier abgestellt gehoert. */
  .nav-layer, .navbar, .nav-drill, .nav-level { transition: none; }
}
/* Das Zeichen der Rubrik - dasselbe wie ueber der Ueberschrift einer
   Eintragsseite. Kraeftiger als die Beschriftung daneben: Es ist die Marke der
   Zeile, nicht ihr Kleingedrucktes. */
.nav-group-icon { width: 1.3rem; height: 1.3rem; flex: none; color: var(--nav-ink); }

/* Logo und Wort bleiben auch auf 320 Pixeln, wie sie sind: Nach dem Wegfall des
   Wortzeichens GUIDE teilen sich nur zwei Dinge die Leiste. Ein kleineres Logo
   und ein Knopf ohne Wort waren die Antwort auf ein Platzproblem, das es nicht
   mehr gibt. */


form { display: grid; gap: .6rem; }

/**
 * ===========================================================================
 * **EIN FELD SIEHT UEBERALL GLEICH AUS** (04.09.2026)
 * ===========================================================================
 *
 * Bis heute stand diese Regel **fuenfmal** da, mit drei verschiedenen
 * Innenabstaenden: hier fuer die Suche, in `.feld` fuer Formulare, in
 * `.ed-merkmal` und den Zeitspalten fuer den Editor, in `.bestand-suche` fuer die
 * Bestandssuche. Nebeneinander sah man es: unterschiedlich hohe Kaesten, mal
 * .55/.7, mal .5/.6, mal .2/.3 - und die Beschriftungen mal fett, mal
 * halbfett, mal grau. Es wirkte unsolide, weil es unsolide war.
 *
 * Jetzt eine Regel fuer jedes Eingabefeld, jede Auswahl und jeden Textkasten:
 *
 *   - **eine Hoehe** (`min-height`), damit ein Feld neben einer Auswahl steht
 *     und nicht darunter zu rutschen scheint,
 *   - **ein Rahmen** (1px `--line`) in jedem Zustand: Der Fokus faerbt ihn,
 *     er zeichnet keinen zweiten. Nichts rueckt, nichts wird dicker.
 *   - **eine Ecke**: 4 px (`--feld-radius`). Flaechen bleiben eckig - das ist
 *     die Marke -, aber was man anfasst, traegt eine leichte Rundung; und
 *     `appearance: none` nimmt der Auswahl die **System**ecke, die macOS ihr
 *     sonst mitgibt, damit die Zahl hier entschieden wird und nicht dort.
 *
 * Was ein Bauteil wirklich unterscheidet, steht bei ihm - die Codekaesten sind
 * gross und zentriert, die Zustandswahl in der Tabelle klein. Alles andere ist
 * hier.
 */
input[type=text], input[type=search], input[type=email], input[type=url],
input[type=tel], input[type=number], input[type=password], input[type=date],
input[type=time], select, textarea {
  font: inherit; color: inherit; background: transparent;
  border: 1px solid var(--line); border-radius: var(--feld-radius);
  padding: .5rem .7rem; min-height: var(--feld-hoehe); width: 100%;
}
/**
 * ===========================================================================
 * **A search box is round** - the one shape everybody knows it by
 * ===========================================================================
 *
 * The model is the slot of the search layer (`.suchschlitz`, exception 1 of
 * the style guide's list): round ends, a line for an edge, the words set well
 * inside the curve. It holds for **every** search box of the house, so the
 * same move looks the same wherever it is made - in the layer, over a result
 * list, over a calendar, over a table in the backend.
 *
 * **It hangs on named parts, not on `type="search"`.** That attribute is set
 * for behaviour - the clear button on iOS, `enterkeyhint`, the combobox role -
 * and a shape hanging off it would leave the next search box written as
 * `type="text"` square, with nobody noticing, because it would look right.
 * The list below is the roster: to add one, name it here.
 *
 * **Out here only, not in the backend.** The line is not who is looking, it
 * is what the field is. Out here the search **is** the instrument of its
 * surface and stands alone; in the backend it is a row in a form, sitting in
 * a `.feld` among square fields, selects, tabs and rails - and two of them
 * (`#eintraege-suche`, `.hb-suche`) are comboboxes with a square panel of
 * results under them. Round would not say "this is a search" there, it would
 * say "this one field is different from the eight beside it".
 *
 * **The padding grows with the corners** (`1.1rem` across against `.7rem`):
 * in a round end, text set at `.7rem` sits in the curve. Everything else
 * stays as the base rule has it - one height, one line, one focus colour.
 *
 * `.suchschlitz` is not in the list. It carries its own, larger measurements
 * (magnifier, `1rem 0`, `1.05rem` type) and is the thing being quoted here.
 * =========================================================================== */
.placelayer-search input,
#mp-suche {
  border-radius: 999px;
  padding-inline: 1.1rem;
}
/**
 * **Warum 2,8 rem und nicht 2,6** (05.09.2026).
 *
 * Mit 2,6 rem (41,6 px) griff der Boden nie: Ein Textfeld wird von allein
 * 42,8 px hoch, ein Datums- oder Uhrzeitfeld 44,8 px - der Browser bringt fuer
 * die zwei einen eigenen Editor mit, dessen Zeile hoeher ist als eine
 * Textzeile. Die gemeinsame Hoehe stand also da und tat nichts; nebeneinander
 * waren die Felder trotzdem 2 px auseinander.
 *
 * 2,8 rem (44,8 px) ist genau die Hoehe, die Datum und Uhrzeit von sich aus
 * haben. Damit **greift** der Boden fuer alle anderen, und jedes einzeilige
 * Feld ist gleich hoch - Text, Auswahl, Datum, Uhrzeit, Suche. Nebenbei ist es
 * die Groesse, die sich mit dem Finger treffen laesst.
 *
 * Was hoeher ist, bleibt hoeher: der Textkasten (6 rem, gleich darunter), die
 * Codekaesten (2 rem Schrift) und das Suchfeld in der Leiste. Ein Boden
 * schneidet nichts ab.
 */
textarea { resize: vertical; min-height: 6rem; line-height: 1.5; }
/**
 * **Die Auswahl traegt ihr eigenes Zeichen.** Ohne `appearance: none` zeichnet
 * das System sie: runde Ecken, ein anderer Pfeil, eine andere Hoehe - drei
 * Abweichungen, die keine Absicht sind. Der Pfeil ist derselbe Chevron wie in
 * der Navigation, als Token, damit er im Dunkeln mitzieht.
 */
select {
  appearance: none;
  padding-right: 2rem;
  background-image: var(--chevron);
  background-repeat: no-repeat;
  background-position: right .6rem center;
  background-size: var(--chevron-groesse);
}
/**
 * **The section navigation** (`BFPEditor.abschnittWahl`) - one list of links
 * for six surfaces, in two forms. The frame (`.abschnitt-rahmen`) holds the
 * navigation and the content beside or below it, and it is the query
 * container: the form follows the width the content has, not the window's -
 * the page editor stands beside a column of its own, and at the same window
 * it has less room than the entry editor.
 *
 * **Narrow** (the default): the button under the head, full width, and the
 * list is its dropdown - the house's disclosure toggles `hidden`. **From
 * 56 rem**: the list as a column left of the form whatever `hidden` says, the
 * button gone.
 *
 * **One gap to the head on every surface:** the frame's top margin is the
 * largest bottom margin a head carries (`.ed-kopf`, 2rem). Margins collapse,
 * so the larger of the two wins - every head's own distance disappears in it.
 */
.abschnitt-rahmen {
  container: abschnitt / inline-size;
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  margin-top: 2rem;
  /* A query container does not size itself by its content - in a box that
     shrinks to fit (a flex row, the styleguide's specimen) it would be zero
     wide. It takes the width it stands in. */
  width: 100%;
}
/* A place drawn into by a surface ("Mein Eintrag", the guest folder) is no
   box of its own - the navigation inside it is the grid's child. */
.abschnitt-platz { display: contents; }
.abschnitt-nav, .abschnitt-inhalt { grid-column: 1 / -1; min-width: 0; }
/* The dropdown lies over the content: both are layers of their own, the
   navigation the upper one - a positioned card in the content cannot climb
   over it. */
.abschnitt-nav { position: relative; z-index: 1; margin-bottom: 1.5rem; }
.abschnitt-inhalt { position: relative; z-index: 0; }

/**
 * **One edge for button and dropdown** - the grey line around the button runs
 * on around the open list, so the two read as one box. `--line` alone is too
 * faint for that on the card ground; the edge is the soft grey mixed toward
 * the paper, in both modes.
 */
.abschnitt-nav { --abschnitt-kante: color-mix(in srgb, var(--soft) 45%, var(--paper)); }
/**
 * **The dropdown of the narrow form** - the same list as the column, right
 * under the button, as wide as the content, over it. It is a panel, so it
 * has an edge: card ground, a hairline, the card shadow - tokens only, light
 * and dark. Square like everything of the house. It scrolls in itself when
 * the list is taller than the window allows.
 */
.abschnitt-nav .abschnitt-liste {
  position: absolute; top: 100%; left: 0; right: 0;
  max-height: min(70dvh, 36rem); overflow-y: auto; overscroll-behavior: contain;
  padding: 1rem 1.1rem; border: 1px solid var(--abschnitt-kante); border-top: 0; border-radius: 0;
  background: var(--card-ground); box-shadow: var(--card-shadow);
}
/* A thumb's height per row in the dropdown. */
.abschnitt-nav .abschnitt-liste a { min-height: 44px; align-items: center; }
.abschnitt-nav .abschnitt-liste a .nav-icon { margin-top: 0; }

/**
 * **The button of the narrow form** - it names where you are: small above,
 * in the monospace, the surface; below it, strong, the section. A thumb's
 * height at least (44 px), the chevron on the right like every control that
 * opens something. It does not stick: it belongs to the head, not to the
 * scrolling form.
 */
.abschnitt-knopf {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  width: 100%; min-height: 44px; margin: 0; padding: .45rem .8rem;
  border: 1px solid var(--abschnitt-kante); border-radius: 0; background: var(--paper); color: var(--strong);
  font: inherit; text-align: left; cursor: pointer;
}
.abschnitt-knopf:hover { border-color: var(--soft); }
.abschnitt-knopf:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
.abschnitt-knopf-text { display: grid; gap: .1rem; min-width: 0; }
.abschnitt-knopf-flaeche { font-family: var(--mono); font-size: .72rem; color: var(--soft); }
.abschnitt-knopf-wort {
  font-size: 1rem; color: var(--strong);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.abschnitt-knopf-wort [data-knopf-offen] { color: var(--soft); font-size: .88rem; }
/* The chevron as large as the one on the account button in the bar. */
.abschnitt-knopf .nav-icon { flex: none; width: 1.25rem; height: 1.25rem; }
/* Open, the chevron turns - the same sign, pointing at the way back. */
.abschnitt-knopf[aria-expanded="true"] .nav-icon { transform: rotate(180deg); }

/**
 * **The rows** - the form of the backend's main navigation and the
 * documentation's section list (`.hb-gruppe a`, whose rule names these rows
 * too): a line on the left, always there and grey, strong at the open
 * section; the text soft, strong where you are; never bold. Here the row
 * carries a sign before its word, so it is a flex row.
 */
.abschnitt-liste ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .1rem; }
.abschnitt-liste a {
  display: flex; align-items: flex-start; gap: .55rem; min-height: 2.25rem; cursor: pointer;
}
.abschnitt-liste a .nav-icon { flex: none; width: 1.05rem; height: 1.05rem; margin-top: .1rem; }
.abschnitt-name { display: grid; min-width: 0; }
/* "nicht gespeichert" - a word as a second small line, not a dot. */
.abschnitt-offen { font-size: .78rem; color: var(--soft); line-height: 1.3; }
.abschnitt-offen[hidden] { display: none; }
/* **Held once** - the link that was clicked with unsaved input elsewhere:
   the next click discards. The line turns dashed and strong, the message in
   the bar says why. */
.abschnitt-liste a[data-halt] { border-left-style: dashed; border-left-color: var(--strong); color: var(--strong); }
/* The group word: monospace, small, spaced capitals - no lines between the
   groups, the gap separates. */
.abschnitt-gruppe + .abschnitt-gruppe { margin-top: 1.1rem; }
.abschnitt-gruppenwort {
  margin: 0 0 .35rem; font-family: var(--mono); font-size: .68rem;
  letter-spacing: .08em; text-transform: uppercase; color: var(--soft);
}

/**
 * **The column** - 15 rem, 2.5 rem to the form, no card, no ground, no line,
 * no shadow, no title: it is navigation, not content. It sticks below the
 * backend's bar at the top (`.bk-kopfleiste`, `--navheight` high) and scrolls
 * in itself when it is taller than the window - eighteen sections in the
 * entry editor are.
 * "Weiter" is the same way twice beside it, so it goes.
 */
@container abschnitt (min-width: 56rem) {
  .abschnitt-knopf { display: none; }
  /* The column shows the list whatever the dropdown's `hidden` says, and
     takes back everything that made it a panel. `!important` answers the
     house rule `[hidden] { display: none !important }` - with more weight,
     so it wins here and nowhere else. */
  .abschnitt-nav .abschnitt-liste,
  .abschnitt-nav .abschnitt-liste[hidden] {
    display: block !important; position: static; max-height: none; overflow: visible;
    padding: 0; border: 0; background: none; box-shadow: none;
  }
  .abschnitt-nav .abschnitt-liste a { min-height: 2.25rem; align-items: flex-start; }
  .abschnitt-nav .abschnitt-liste a .nav-icon { margin-top: .1rem; }
  .abschnitt-nav {
    grid-column: 1; grid-row: 1; width: 15rem; margin: 0 2.5rem 0 0;
    align-self: start; position: sticky; top: calc(var(--navheight, 3.7rem) + 1.5rem);
    max-height: calc(100dvh - var(--navheight, 3.7rem) - 3rem); overflow-y: auto; overscroll-behavior: contain;
  }
  .abschnitt-inhalt { grid-column: 2; grid-row: 1; }
  .abschnitt-weiter { display: none; }
}

.abschnitt-weiter { margin: .75rem 0 0; }
/* The arrow of the frontend navigation behind the word, at the size of the text. */
.abschnitt-weiter button { display: inline-flex; align-items: center; gap: .35rem; }
.abschnitt-weiter .nav-icon, .tab-ziel .nav-icon { width: 1em; height: 1em; flex: none; }
.tab-ziel { display: inline-flex; align-items: center; gap: .3rem; }
/* Beim Zeigen dunkelt der Rahmen an - eine Auskunft, dass hier etwas geht. */
input:hover:not(:disabled), select:hover:not(:disabled), textarea:hover:not(:disabled) {
  border-color: var(--soft);
}
/**
 * **Der Fokus faerbt den Rahmen schwarz** - er legt keinen zweiten Strich
 * darum. Zwei Fassungen davor waren falsch: ein Ring innen (das Feld sah aus,
 * als schrumpfe es) und ein Ring aussen (ein zweiter Strich um etwas, das
 * schon einen hat).
 */
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: none; border-color: var(--strong);
}
/**
 * In der Kontrastdarstellung des Systems setzt der Rechner die Farben selbst -
 * ein Fokus, der **nur** ueber eine Farbe spricht, waere dort unsichtbar. Dann
 * kommt der Umriss zurueck.
 */
@media (forced-colors: active) {
  input:focus-visible, select:focus-visible, textarea:focus-visible {
    outline: 2px solid; outline-offset: 1px;
  }
}
input:disabled, select:disabled, textarea:disabled {
  background: var(--shade); color: var(--soft); cursor: not-allowed;
}
/**
 * **Der Haken gehoert dazu** (05.09.2026).
 *
 * Zu ihm stand hier bisher nichts - und deshalb zeichnete ihn das System:
 * 13 px klein neben 44,8 px hohen Feldern und in Systemblau, einer Farbe, die
 * es im Guide sonst nirgends gibt. Auf der Seite mit den Gattungen sind das
 * siebzehn blaue Kaestchen; das war der unsolideste Fleck im Formular.
 *
 * `accent-color` ist der ganze Eingriff. Ein selbstgezeichneter Haken
 * (`appearance: none` und ein Bild darin) saehe gleich aus und koennte danach
 * in vier Zustaenden falsch sein - unbestimmt, abgeschaltet, im Hochkontrast,
 * im dunklen Modus. Der Browser kann das alles schon.
 *
 * **Die Ausnahme beim Fokus, und ihr Grund:** Ueberall sonst faerbt der Fokus
 * den Rahmen. Ein Haken hat keinen Rahmen von uns - `border-color` traefe das
 * Kaestchen des Systems nicht. Er bekommt deshalb als Einziger einen Umriss;
 * `outline-offset` haelt ihn vom Kaestchen ab, damit man beide sieht.
 *
 * **Fuer den Tag, an dem der Dunkelmodus angeht:** Das leere Kaestchen ist
 * dann ein weiss gefuelltes Quadrat, weil oben `color-scheme: light` steht und
 * der Browser es entsprechend zeichnet. Mit `light dark` sitzt es richtig -
 * das gehoert zu dem einen Handgriff, der oben bei der Palette beschrieben ist.
 */
input[type=checkbox], input[type=radio] {
  accent-color: var(--strong);
  /* `flex: none`, weil ein Kaestchen oft in einer Flex-Zeile steht: ohne den
     Riegel schrumpft es dort zum Rechteck, sobald die Zeile eng wird. */
  width: 1.1rem; height: 1.1rem; flex: none;
}
input[type=checkbox]:focus-visible, input[type=radio]:focus-visible {
  outline: 2px solid var(--strong); outline-offset: 2px;
}
button {
  font: inherit; color: inherit; background: transparent;
  border: 1px solid var(--line); padding: .55rem .7rem;
}

/**
 * **Das X zum Leeren - schwarz, klickbar, gleicher Strich wie ueberall.**
 *
 * Der Browser bringt es selbst mit (`::-webkit-search-cancel-button`), aber in
 * seiner eigenen Fassung: hellgrau, in einer fremden Strichstaerke, und ohne
 * Zeiger unter der Maus - man sieht ihm nicht an, dass es ein Knopf ist.
 *
 * Ersetzt wird es durch **dasselbe Kreuz wie im Aufklapper und in der Galerie**:
 * derselbe Pfad wie `icon("close")` in `chrome.js` (viewBox 17, Strich 1.3,
 * runde Enden), hier als Maske. Als Maske und nicht als Bild, damit die Farbe
 * aus `--strong` kommt und in hell wie dunkel stimmt - dieselbe Ueberlegung
 * wie beim Zeichen im Fuss.
 *
 * **Der Pfad steht damit an zwei Stellen**, und das ist bewusst: CSS kann kein
 * Skript aufrufen, und ein Zeichen, das der Browser selbst einsetzt, kann kein
 * `<svg>` aus dem Dokument sein. Der Kommentar hier ist die Klammer - aendert
 * sich das Kreuz, aendert es sich zweimal.
 *
 * Gilt fuer **alle** Suchfelder: die Suche, die Karte und den Ort. Deshalb hier
 * an der Grundregel und nicht bei einer einzelnen Zeile.
 */
input[type=search]::-webkit-search-cancel-button {
  -webkit-appearance: none; appearance: none;
  width: 1rem; height: 1rem;
  cursor: pointer;
  background: var(--strong);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.6 3.6l9.8 9.8M13.4 3.6l-9.8 9.8'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.6 3.6l9.8 9.8M13.4 3.6l-9.8 9.8'/%3E%3C/svg%3E") center / contain no-repeat;
}
.row { display: flex; gap: .6rem; }
#locate { flex: 1; cursor: pointer; }
#locate[aria-busy=true] { opacity: .6; }
/* ---------------------------------------------------------------------------
   Die Suchzeile: was links, wo rechts.
   ---------------------------------------------------------------------------

   Eine Zeile, zwei Fragen - dieselbe Ordnung, die jeder von einer Suche kennt.
   Der rechte Griff oeffnet die Ortswahl als Layer, weil dort drei Wege liegen
   (Satellit, Ortsname, ganzer Schwarzwald) und drei Wege nicht in eine Zeile
   passen. */
/* Der Titel der Themenseite: die Ueberschrift, unter der alles steht. */
#pagetitle { margin: 0 0 .2rem; }

/* **Runde Enden wie jedes Suchfeld** - siehe „A search box is round". Sie ist
   zusammengesetzt (Feld links, Ortsknopf rechts), also bekommt jede Haelfte
   die Rundung ihrer Aussenkante; die Trennlinie in der Mitte bleibt gerade.
   Das Feld ist die Frage, der Knopf ihre Reichweite - zwei Faecher einer
   Zeile, nicht zwei Enden einer Bahn. */
.searchbar {
  display: flex; align-items: stretch; gap: 0;
  border: 1px solid var(--strong); border-radius: 999px; background: var(--paper);
  /* Nach oben Luft, aber knapp: Der Titel ist das Thema der Seite, die Zeile
     darunter das Werkzeug dazu - sie gehoeren zusammen. 1,8 rem trennten
     beides in zwei Bloecke, .5 rem klebte sie aneinander. */
  margin: 1.1rem 0 1rem;
}
.searchbar input[type=search] {
  flex: 1; min-width: 0; border: 0; background: none;
  border-radius: 999px 0 0 999px;
  padding: .8rem 1rem .8rem 1.3rem; font: inherit; font-size: 1rem;
}
/* Hier bleibt der Ring **innen**, anders als bei `.feld input` - und das ist
   kein Versehen: Dieses Feld hat keinen eigenen Rahmen (den traegt die Leiste)
   und sitzt bündig neben dem Ortsknopf. Ein aeusserer Ring liefe ueber beides.
   Weil nichts ueberlagert wird, sieht es hier auch nicht nach Schrumpfen aus. */
.searchbar input[type=search]:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
.searchbar-place {
  display: inline-flex; align-items: center; gap: .4rem;
  border: 0; border-left: 1px solid var(--line); background: none;
  border-radius: 0 999px 999px 0;
  padding: .8rem 1.3rem .8rem 1rem; font: inherit; font-size: .95rem; color: var(--soft);
  cursor: pointer; white-space: nowrap; max-width: 45%;
}
.searchbar-place > span {
  display: inline-flex; align-items: center; gap: .4rem; min-width: 0;
}
.searchbar-place > span > span { overflow: hidden; text-overflow: ellipsis; }
/* Der Pin nimmt die Farbe der Zeile an: gedaempft, solange kein Ort gesetzt
   ist, kraeftig sobald einer dasteht. */
.searchbar-place .pin-icon { stroke: currentColor; fill: currentColor; }
.searchbar-place:hover { color: var(--strong); }
/* Ist ein Ort gesetzt, ist er kein Hinweis mehr, sondern eine Angabe. */
.searchbar-place.is-set { color: var(--strong); font-weight: 700; }
.searchbar-place:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
/**
 * **Auf dem Telefon nur die Nadel.**
 *
 * „Ganzer Schwarzwald" braucht neben der Nadel rund 150 px; der Knopf darf
 * hoechstens 45 % der Leiste nehmen, und die ist auf einem Telefon 358 px
 * breit - das Wort endete in Auslassungspunkten, und das Suchfeld daneben
 * verlor die Haelfte seiner Breite an einen abgeschnittenen Satz. **Gemessen
 * passt er bis rund 30 rem**, darunter nicht mehr.
 *
 * Die Nadel sagt dasselbe, weil sie ihre **Farbe** hat: leise, solange der
 * ganze Schwarzwald gilt, und schwarz, sobald ein Ort gesetzt ist
 * (`.is-set`) - dieselbe Regel wie beim Wort, nur ohne Buchstaben. Den Namen
 * traegt das `aria-label`, und es wird bei jeder Wahl neu gesetzt.
 */
@media (max-width: 30rem) {
  .searchbar-place { max-width: none; padding: .8rem 1.1rem; }
  .searchbar-place > span > span { display: none; }
  /* **Und die Nadel waechst**: Neben einem Wort ist sie eine Marke, allein ist
     sie das Ziel - und ein Ziel von zehn Pixeln trifft kein Daumen sicher.
     Die Flaeche bleibt der ganze Knopf, aber man muss sehen, worauf man
     zielt. */
  .searchbar-place .pin-icon { width: .95rem; height: 1.15rem; }
}

/* Zahl und Reihenfolge in einer Zeile - die Zahl sagt, was da ist, die Auswahl
   daneben, in welcher Ordnung. */
/* **Die Gattungen als Pillen** (05.09.2026) - wischbar, die aktive gefuellt.
   Runde Ecken sind hier die Ausnahme mit demselben Grund wie beim Suchschlitz:
   Eine Pille ist ein gelerntes Bauteil fuer „eine Auswahl aus wenigen". */
.gattungs-pillen {
  display: flex; gap: .4rem; margin: .8rem 0 0;
  overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
}
.gattungs-pillen::-webkit-scrollbar { height: 0; }
/**
 * **So hoch wie der Umschalter daneben** (`--regler-hoehe`). Beide stehen auf
 * derselben Seite und werden mit demselben Daumen getroffen; zwei Hoehen sind
 * zwei Bauteile, und das sieht man in der Sekunde, in der sie untereinander
 * stehen. Das Polster steht deshalb nur noch waagerecht - die Hoehe kommt aus
 * der Zahl, nicht aus der Schriftgroesse.
 */
.gattungs-pillen a {
  display: inline-flex; align-items: center; gap: .4rem; white-space: nowrap;
  min-height: var(--regler-hoehe);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 0 .9rem; font-size: .82rem; color: var(--ink); text-decoration: none;
}
.gattungs-pillen a:hover { border-color: var(--strong); }
.gattungs-pillen a[aria-current="page"] {
  background: var(--strong); border-color: var(--strong); color: var(--paper);
}
/**
 * **Die Zahl ist gezaehlt, also traegt sie die Monospace** - dieselbe Klasse
 * Angabe wie die Entfernung in der Mappe oder die Spalte „Ohne Ergebnis" in
 * den Suchbegriffen: Was die Software rechnet, traegt ihre Schrift. `tabular-nums`
 * bleibt, damit 9 und 90 nicht verschieden breit sitzen.
 */
.gattungs-pillen .pille-zahl {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  opacity: .65; font-size: .8em;
}

.count-row {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: .4rem 1rem; margin: 1rem 0 .8rem;
}

/* ===========================================================================
   **The filter of `/karte/`** - a button beside the list/map switch, a flap
   under them, one row per category (`app.js filterMarkup`).
   ===========================================================================

   The pills are the form of `.gattungs-pillen` - same height as the switch
   (`--regler-hoehe`), round ends - but they wrap:
   22 kinds are no swipe. Under each pill sits a **real checkbox**, laid over
   the whole pill and invisible; keyboard, screen reader and the click target
   come from the browser, the ring goes around the pill (`:has(:focus-visible)`).

   The state is the surface, never the weight:
   - a chosen category is full in its colour, the white mark on it;
   - a chosen kind is the tint of that colour (18 % to paper), as in the head
     line above an entry;
   - a chosen category tints all its kinds ("all of them are in");
   - a category with a chosen kind is half set (`indeterminate`) and keeps its
     edge in the colour.
   Colour comes in as `--rf` / `--rf-voll` on the row, gold reads its ink. */
.filter-reihe {
  display: flex; align-items: center; justify-content: space-between; gap: .6rem;
  margin: 1rem 0 0;
}
.filter-reihe .viewtabs { margin: 0 0 0 auto; }
.filter-knopf {
  display: inline-flex; align-items: center; gap: .45rem;
  min-height: var(--regler-hoehe); padding: 0 .95rem;
  border: 1px solid var(--line); border-radius: 999px; background: var(--paper);
  color: var(--strong); font-size: .82rem; cursor: pointer;
}
.filter-knopf:hover,
.filter-knopf[aria-expanded="true"] { border-color: var(--strong); }
.filter-knopf:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
.filter-knopf .nav-icon { width: .95rem; height: .95rem; flex: none; }
/* The number on the button is a state, so it is filled - and counted, so it
   is in the monospace. */
.filter-knopf .pille-zahl {
  min-width: 1.35rem; padding: 0 .35rem; border-radius: 999px;
  background: var(--strong); color: var(--paper);
  font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: .72rem;
  line-height: 1.35rem; text-align: center;
}
/* Between two categories more air than inside one: on a phone a row wraps,
   and with the same gap the four groups ran into one field of pills. */
.filter-flaeche {
  display: grid; gap: 1rem; margin: .8rem 0 0; padding: .9rem 0 0;
  border-top: 1px solid var(--line);
}
.filter-zeile { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.filter-pille {
  position: relative; display: inline-flex; align-items: center; gap: .4rem;
  min-height: var(--regler-hoehe); padding: 0 .9rem;
  border: 1px solid var(--line); border-radius: 999px; background: var(--paper);
  color: var(--ink); font-size: .82rem; white-space: nowrap; cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
@media (prefers-reduced-motion: reduce) { .filter-pille { transition: none; } }
/* The element in the selector beats the house rule for checkboxes, which
   sets 1.1 rem and would leave a square inside the pill. */
.filter-pille input[type="checkbox"] {
  position: absolute; inset: 0; width: 100%; height: 100%; margin: 0;
  appearance: none; opacity: 0; cursor: pointer;
}
.filter-pille:hover { border-color: var(--strong); }
.filter-pille:has(input:focus-visible) { outline: 2px solid var(--strong); outline-offset: 2px; }
.filter-zeichen { width: 1.15rem; height: 1.15rem; flex: none; color: var(--rf-voll); }
:root[data-theme="dark"] .filter-zeichen { color: color-mix(in srgb, var(--rf-voll) 50%, var(--strong)); }
.filter-rubrik:has(input:checked) {
  background: var(--rf-voll); border-color: var(--rf-voll); color: var(--auf-bild-ink);
}
.filter-rubrik:has(input:checked) .filter-zeichen { color: inherit; }
.filter-rubrik:has(input:indeterminate) { border-color: var(--rf-voll); }
.filter-zeile:has(.filter-rubrik input:checked) .filter-pille:not(.filter-rubrik),
.filter-pille:not(.filter-rubrik):has(input:checked) {
  background: color-mix(in srgb, var(--rf) 18%, var(--paper)); color: var(--strong);
}
.filter-pille:not(.filter-rubrik):has(input:checked) { border-color: var(--rf-voll); }
/* A thumb needs 44 px; the pill stays at the height of the switch, the grip
   grows above and below it. */
@media (pointer: coarse) {
  .filter-zeile { row-gap: .5rem; }
  .filter-pille::before { content: ""; position: absolute; inset: -4px 0; }
}
/* What is set stands next to the number, with the one way back. */
.count-row:has(.filter-stand:not([hidden])) { justify-content: flex-start; }
.filter-stand { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: .3rem .8rem; }
.filter-stand[hidden] { display: none; }
.filter-namen { color: var(--soft); font-size: .82rem; }
.filter-namen::before { content: "· "; }
.filter-stand .linklike { font-size: .82rem; }

/**
 * **Die Ortswahl traegt eine Kopfzeile** - „Wo suchst du?" links, das X rechts,
 * dieselbe Zeile wie jede Schicht des Hauses (`.schicht-kopf`). Damit faellt
 * der obere Abstand des Layers weg: Er hielt den Platz fuer das freistehende
 * Quadrat frei, und die Zeile **ist** jetzt dieser Platz.
 *
 * Aus dem Raster wird eine Spalte, weil nur noch **der Inhalt** rollen soll -
 * bei 240 Orten bleiben Name und Ausgang sonst nicht stehen. Der Inhalt behaelt
 * seine eigene Breite (`.langlayer-inner`) und wird mit `margin-inline: auto`
 * mittig gestellt; `min-height: 0` ist die Bedingung dafuer, dass ein Kind in
 * einer Flex-Spalte ueberhaupt kleiner werden darf als sein Inhalt.
 *
 * Die Sprachwahl bleibt, wie sie war: Sie traegt eine Liste aus sechs Zeilen
 * und keine Frage, die man mit einem Suchfeld beantwortet.
 */
.placelayer.langlayer[open] {
  display: flex; flex-direction: column; align-items: stretch;
  padding-block: 0; overflow: hidden;
}
.placelayer .langlayer-inner {
  margin-inline: auto; min-height: 0; overflow-y: auto;
  padding-block: 1.4rem 2.5rem;
}

/* Die Ortswahl - dieselbe Bauart wie die Sprachwahl (`.langlayer`), nur mit
   drei Wegen darin. */
.placelayer-inner { display: grid; gap: .9rem; }
.placelayer-inner .action { justify-content: center; }
/* Der Pin vor „Meinen Standort verwenden" - dasselbe Zeichen wie auf dem Knopf,
   der diese Schicht oeffnet, und vor jedem Ortsnamen im Guide. Er nimmt die
   Farbe des Knopfs an (`currentColor`): Der schwarze Knopf dreht sich beim
   Zeigen um, und ein Pin in `--strong` waere darauf einmal unsichtbar. */
.placelayer-inner .action .pin-icon { stroke: currentColor; fill: currentColor; }
.placelayer-hint { margin: 0; color: var(--soft); font-size: .85rem; min-height: 1.2em; }
/* Der Ort steht in Schriftfarbe, der Satz drumherum leise - er ist die
   Angabe, nicht die Erklaerung. */
.placelayer-hint strong { color: var(--ink); }
.placelayer-hint .linklike { font-size: inherit; }
.placelayer-search input { width: 100%; }
/* The radius sits between the state line and the search: first how far, then
   around where. The fieldset keeps no bottom margin - the grid gap spaces it. */
.placelayer-umkreis { margin: 0; }
/**
 * **The radius is a track, not four pills** - one question, four answers,
 * and the steps are ordered (near to far). It borrows the shape of the
 * list/map switch (`.viewtabs`): grey rail, black track, quiet words on the
 * rail. Written out and not shared, for the reason given there: the looks
 * are the same, the controls are not (radios here, tabs there).
 *
 * **Four equal steps across the full width.** The travelling track needs
 * equal fields to be computed in percent, and the layer is the width a
 * phone has: four times 1fr leaves about 80 px each at 390 px, and the
 * longest word ("ohne Grenze", "sans limite") needs about 75. `minmax(0, 1fr)`
 * holds the four equal - a plain `1fr` grows the column of the longest word,
 * and the track sat beside its field.
 */
.umkreis-bahn {
  position: relative;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 0;
  min-height: var(--regler-hoehe); padding: 2px;
  border-radius: 999px; background: var(--shade);
}
.umkreis-bahn::before {
  content: ""; position: absolute; z-index: 0; top: 2px; bottom: 2px; left: 2px;
  width: calc((100% - 4px) / 4); border-radius: 999px;
  background: var(--strong); transition: transform .18s ease;
}
.umkreis-bahn:has(.wahl:nth-child(2) input:checked)::before { transform: translateX(100%); }
.umkreis-bahn:has(.wahl:nth-child(3) input:checked)::before { transform: translateX(200%); }
.umkreis-bahn:has(.wahl:nth-child(4) input:checked)::before { transform: translateX(300%); }
@media (prefers-reduced-motion: reduce) {
  .umkreis-bahn::before { transition: none; }
}
.umkreis-bahn .wahl {
  position: relative; z-index: 1; justify-content: center;
  border: 0; border-radius: 999px; background: none; color: var(--soft);
  padding: .26rem .15rem; font-size: .8rem; white-space: nowrap;
  transition: color .18s ease;
}
.umkreis-bahn .wahl:not(:has(input:checked)):hover { color: var(--strong); }
/* The chosen state is the track underneath - the label carries only the word. */
.umkreis-bahn .wahl:has(input:checked) { background: none; color: var(--paper); }
/* The ring belongs around the whole control, as on the list/map switch. */
.umkreis-bahn:has(input:focus-visible) { outline: 2px solid var(--strong); outline-offset: 2px; }
.umkreis-bahn .wahl:has(input:focus-visible) { outline: none; }
/* Below 24rem the longest word touches the track's round ends - one size down. */
@media (max-width: 24rem) {
  .umkreis-bahn .wahl { font-size: .74rem; }
}
@media (forced-colors: active) {
  .umkreis-bahn .wahl:has(input:checked) { outline: 2px solid; outline-offset: -4px; }
}
.placelayer ul { max-height: 32vh; overflow-y: auto; }
.placelayer li button {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem; width: 100%;
  border: 0; background: none; padding: .7rem .2rem; font: inherit; font-size: 1.05rem;
  color: var(--ink); cursor: pointer; text-align: left;
  border-bottom: 1px solid var(--line);
}
.placelayer li button:hover, .placelayer li button:focus-visible { background: var(--shade); }
.placelayer-count { color: var(--soft); font-size: .85rem; font-variant-numeric: tabular-nums; }


.tabs { display: flex; flex-wrap: wrap; gap: .4rem; margin: 1.3rem 0 .8rem; }
.tabs button {
  cursor: pointer; padding: .3rem .8rem; font-size: .88rem;
}
.tabs button[aria-pressed=true] { background: var(--accent); border-color: var(--accent); color: var(--paper); }
.tabs button:disabled { opacity: .35; cursor: default; }
.tabs .n { color: inherit; opacity: .65; }

.count { color: var(--soft); font-size: .82rem; margin: 0 0 .4rem; }
.results { list-style: none; padding: 0; margin: 0; }
.results li { border-top: 1px solid var(--line); padding: .7rem 0; }
.results h2 { font-size: 1rem; margin: 0 0 .15rem; }
/**
 * **Diese Regel gehoert der Zeile, nicht der Kachel** (09.09.2026).
 *
 * `.results p` traf jeden Absatz **in** einer Kachel mit: Auf der Suchseite
 * standen Ort und Kurzbeschreibung damit auf .86rem ohne Abstaende, auf der
 * Startseite in ihrer eigenen Groesse - dieselbe Komponente, zwei Aussehen.
 * Gemessen: 13,76 px gegen 16,8 px.
 *
 * Eine Trefferliste kennt zwei Gestalten: **Zeilen** (auf der Eintragsseite,
 * „was in der Naehe liegt") und **Kacheln** (Suche, Startseite). `:has()`
 * fragt danach - dieselbe Frage, mit der zwei Regeln weiter unten Linie und
 * Polster der Zeile verschwinden.
 */
.results li:not(:has(.card)) p { margin: 0; color: var(--soft); font-size: .86rem; }

/**
 * **Traegt eine Trefferzeile eine Kachel, verschwindet die Zeile.**
 *
 * Die Kachel bringt ihren eigenen Rahmen und ihre eigenen Abstaende mit; Linie
 * und Polster der Liste kaemen doppelt. `:has()` fragt danach, statt eine
 * zweite Klasse zu verlangen - so bleibt die Liste dieselbe, egal ob sie
 * Kacheln oder Zeilen enthaelt (auf der Eintragsseite sind es Zeilen).
 */
.results li:has(.card) { border-top: 0; padding: 0; }
/**
 * **Ein Kachelraster, drei Orte** - die Trefferliste teilt sich Abstaende und
 * Spalten mit „Neu im Guide" und den Kacheln einer Ortsseite. Die Regel steht
 * einmal, bei `#neu`; eine Kachelliste, die auf der Suchseite anders bricht
 * als auf der Startseite, waere dieselbe Komponente in einer zweiten
 * Anordnung.
 *
 * Was hier bleibt, ist nur, **was diese Liste ausmacht**: Sie ist ein `ul`,
 * und ihre Zeilen tragen wahlweise Kacheln oder Zeilen (`:has(.card)`).
 */
.results:has(.card) { display: grid; }
.km { float: right; color: var(--soft); font-size: .84rem; font-variant-numeric: tabular-nums; }
/* Der alte, weisse Fuss ist entfallen - seine Abstaende stehen jetzt in
   `footer.foot`, damit die Schraege ihre eigene Rechnung hat. */
.note { color: var(--soft); font-size: .78rem; }

/* Beitragskarte. Die Farben sind neutral, bis die Markenfarben eingebunden sind. */
.map { margin: 1.4rem 0; text-align: center; }
.map svg { max-width: 100%; height: auto; }
/**
 * Die Kontur in Schwarz - sie ist das primaere Element der Karte, nicht eine
 * Trennlinie.
 *
 * **`non-scaling-stroke` fehlte, und dadurch passten Pin und Kontur nicht
 * zueinander.** Der Kommentar hier behauptete es seit Wochen, die Regel stand
 * aber nirgends. Folge: Die Kontur bekam 1,2 Pixel, der Pin ebenfalls - nur
 * steckt der Pin in einer Gruppe mit `scale(0,19)`, und ein skalierter Strich
 * skaliert mit. Aus 1,2 wurden 0,22 Pixel, also ein Haar neben einer Linie.
 *
 * Mit `non-scaling-stroke` rechnet der Browser den Strich **nach** der
 * Skalierung: Beide tragen jetzt dieselbe Staerke, und das SVG kann weiter von
 * 90 auf 340 Pixel wachsen, ohne dass die Kontur dicker wird.
 */
.map .outline, .map .pin path, .map .pin circle {
  fill: none; stroke: var(--strong); stroke-width: 1.2;
  vector-effect: non-scaling-stroke;
}
/**
 * **Der Pin ist innen deckend - in der Farbe der Flaeche, auf der er liegt.**
 *
 * Als blosse Kontur liefen die Konturlinien der Karte mitten durch ihn
 * hindurch; er sah aus wie ein Zeichen **hinter** der Zeichnung statt darauf.
 * Gefuellt ist er damit nicht "schwerer": Die Fuellung ist der Grund selbst,
 * sie deckt nur, was hinter ihm liegt.
 *
 * `fill: none` steht als Merkmal im SVG und bleibt dort - ohne Stylesheet
 * zeichnet die Datei dann keine Flaeche, die niemand eingefaerbt hat. Welche
 * Farbe der Grund hat, weiss nur die Seite, und die steht hier.
 */
.map .pin path { fill: var(--paper); }
/* Auf der Buehne der Ortsseite ist der Grund schwarz - dort deckt Schwarz. */
.stage-text .map .pin path { fill: var(--nav); }
/* Der Punkt im Pin ist gefuellt, nicht umrandet - er ist die Spitze der
   Aussage, nicht ihre Kante. */
.map .pin circle { fill: var(--strong); stroke: none; }
.map .area { fill: var(--strong); opacity: .10; stroke: none; }
/* Der Pin ist das eine farbige Ding auf der Karte. Welche Farbe: offen - die
   fuenf Markenfarben gehoeren fest zu den Magazin-Kategorien und duerfen nicht
   zweckentfremdet werden, und die vier GUIDE-Kategorien sind andere. Bis das
   entschieden ist, eine neutrale Farbe aus der Palette (Body). */
.map .pin { --pin: var(--strong); stroke: var(--pin); fill: var(--pin); }
.map figcaption { color: var(--soft); font-size: .82rem; margin-top: .4rem; }
/**
 * **Die Karte auf der Buehne der Ortsseite** - dieselbe Zeichnung, anderer
 * Grund: Die Textspalte ist schwarz (`--nav`), und Kontur wie Nadel stehen
 * sonst in `--strong`, also schwarz auf schwarz.
 *
 * Die Farbe kommt deshalb von der Spalte selbst (`--nav-ink`), nicht als
 * zweiter fester Wert - wer den Grund der Buehne aendert, aendert die Karte
 * mit. Die Flaeche der Gemeinde wird zur **hellen** Aufhellung: Zehn Prozent
 * Schwarz auf Schwarz sind nichts.
 *
 * **Linksbuendig und kleiner:** Sie steht unter der Einleitung in einer
 * Textspalte, und alles darin beginnt an derselben Kante. Mittig waere sie ein
 * zweiter Block mit einer eigenen Achse.
 */
.stage-text .map { margin: 1.8rem 0 0; text-align: left; }
.stage-text .map svg { height: 11rem; width: auto; }
.stage-text .map .outline,
.stage-text .map .pin path,
.stage-text .map .pin circle { stroke: var(--nav-ink); }
.stage-text .map .pin { --pin: var(--nav-ink); fill: var(--nav-ink); }
.stage-text .map .pin circle { fill: var(--nav-ink); }
.stage-text .map .area { fill: var(--nav-ink); opacity: .22; }
/* Der Weg zurueck: ein **schwarzes Quadrat oben links**, so hoch wie der
   Navigationsblock rechts. Die beiden sind ein Paar an der Oberkante - links
   heraus, rechts hinein.

   `fixed` und nicht `sticky`: Es soll an der Fensterkante kleben, nicht in der
   Inhaltsspalte, und `main` ist auf 1100 begrenzt. Die Hoehe kommt aus
   derselben Messung wie der Block gegenueber (`--navheight`), damit die beiden
   nicht auseinanderlaufen, wenn sich die Schriftgroesse aendert. */
/* **Ein Quadrat fuer alle Wege zurueck.** Der Zurueckknopf oben links auf der
   Eintragsseite und die Knoepfe in der Galerie (Pfeile und X) sind dieselbe
   Sache: eine Ansicht verlassen oder einen Schritt weiter. Ein zweites
   Formenpaar dafuer waeren zwei Sprachen in einer Oberflaeche. */
.backsquare {
  width: var(--navheight, 3.7rem); height: var(--navheight, 3.7rem);
  display: flex; align-items: center; justify-content: center;
  background: var(--nav); color: var(--nav-ink);
  border: 0; padding: 0; cursor: pointer;
}
/* Der Zurueckknopf am Eintrag und der Abmeldeknopf im Profil kleben beide an
   der Ecke der Seite - in der Galerie sitzen die Quadrate dagegen im Raster.
   Ein `<button>` ist es im Profil, weil dort nichts aufgerufen wird, sondern
   eine Sitzung endet. */
a.backsquare { position: fixed; top: 0; left: 0; z-index: 21; }
/* **When the search opens, the way back leaves the page.** The square travels
   out to the left while the magnifier travels right, and the white strip of
   the search takes the corner - its left edge runs on the square's right edge
   (`such-streifen`: the left inset goes from `--ecke-links` to 0 in the first
   half, the same .22 s and the same easing as this transition, so the two
   edges stay together). It comes back when the search has closed
   (`data-suche` is removed at `close`, after the way back). A transition, not
   a keyframe: the state is the search's, the square only follows it. */
a.backsquare { transition: transform .22s ease-in-out; }
html[data-suche="auf"] a.backsquare { transform: translateX(-100%); }
@media (prefers-reduced-motion: reduce) {
  a.backsquare { transition: none; }
}
.backsquare:hover, .backsquare:focus-visible {
  background: color-mix(in srgb, var(--nav) 82%, var(--nav-ink));
}

/**
 * **In der Gaestemappe schwebt der Zurueckknopf unten in der Mitte** - auf jeder Breite,
 * auf dem Telefon wie auf dem Tablet im Zimmer: Die Mappe ist auf jedem Geraet
 * dieselbe App, also steht ihr Rueckweg auch ueberall an derselben Stelle.
 *
 * In der Mappe ist er der **einzige** Weg: Es gibt dort keine Leiste der
 * Huelle und keine Lupe, sondern den schwarzen Kopf des Hauses - und der
 * traegt links das Signet. Oben links stuenden damit zwei Marken
 * uebereinander. Unten in der Mitte liegt er da, wo der Daumen ist, ueberdeckt
 * keine Ueberschrift und hat mit einem Rand ringsum eine sichtbare Kante zum
 * Text darunter. Der **Schatten** ist hier noetig und sonst nicht: Oben sitzt
 * das Quadrat in einer Leiste, hier auf dem Inhalt.
 *
 * **Und er ist dort rund** (siehe `html[data-mappe] a.backsquare#back`):
 * Ein Quadrat, das frei ueber einer Liste liegt, liest sich als
 * abgeschnittene Flaeche; ein Kreis liest sich als Knopf.
 *
 * **Im Guide steht er oben links** - auf Eintrag, Beitrag und Veranstaltung,
 * und die Lupe rueckt ihm zur Seite (`--ecke-links`). **Unter 400 px schwebt
 * er unten in der Mitte** (siehe bei `.suchknopf`): Auf einem kleinen Telefon
 * ist oben links weit weg vom Daumen, und die Ecke bekommt die Lupe.
 */
html[data-mappe] a.backsquare#back {
  /* Centred at the foot of the page: `left` and `right` both 0 with an auto
     margin centre a fixed box of known width without a `transform` - the
     button already uses `transform` for its slide when the search opens. */
  top: auto; left: 0; right: 0; margin-inline: auto;
  bottom: calc(1rem + env(safe-area-inset-bottom));
  box-shadow: 0 4px 16px rgb(0 0 0 / .22);
}
.backsquare:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: -4px; }
.back-icon { width: 1.15rem; height: 1.15rem; }
/**
 * **Die Kurzbeschreibung sieht ueberall gleich aus.**
 *
 * `.lead` ist der eine Satz unter dem Titel einer Seite - auf `/ueber-mich/`,
 * im Magazin, im Kalender, an einem Beitrag, an einem Eintrag, an einer
 * Veranstaltung. Es ist ueberall dieselbe Sache: die Antwort auf „worum geht
 * es hier", bevor der Inhalt anfaengt. Also ist es ueberall dieselbe Form.
 *
 * **Deutlich groesser als der Fliesstext und leiser als er** - das ist der
 * ganze Trick. Die Groesse sagt „lies mich zuerst", die Farbe sagt „ich bin
 * nicht der Text". Ein Vorspann in Textfarbe und Textgroesse ist ein erster
 * Absatz, und dann fehlt der Seite der Einstieg.
 *
 * 1.25 rem sind 20 px - ein Viertel ueber dem Fliesstext und damit ein
 * sichtbarer Sprung, nicht der Hauch von drei Prozent, der vorher zwischen
 * `.lead` und einem Absatz lag. Die Zeilenhoehe geht dabei von 1.55 auf 1.5
 * herunter: Je groesser die Schrift, desto weniger Durchschuss braucht die
 * Zeile - bei 1.55 fiele der Vorspann in Zeilen auseinander, die einzeln
 * dastehen.
 *
 * **Die Lesespalte steht hier**, nicht bei den einzelnen Seiten. Ein Satz, der
 * ueber die ganze Rahmenbreite laeuft, ist ueber hundert Zeichen lang - und
 * ein Vorspann ist der eine Satz, den jeder liest. Vorher sagten drei Seiten
 * das einzeln, und der Kalender sagte es nicht: Dort lief er 1100 px breit,
 * waehrend er nebenan bei 46 rem umbrach.
 *
 * **Der Abstand steht hier nicht.** Was unter dem Satz folgt, ist je Seite
 * etwas anderes - ein Abschnitt, eine Zaehlzeile, eine Suchzeile, ein Bild -,
 * und der Abstand gehoert zu dem, was folgt.
 */
.lead {
  font-size: 1.25rem; line-height: 1.5; color: var(--soft);
  max-width: var(--text);
}
/* **Der Vorspann einer Ergebnisseite** steht zwischen Ueberschrift und
   Suchzeile (17.09.2026) - mit eigener Luft nach oben: Er ist ein eigener Satz
   und keine zweite Zeile der Ueberschrift, und der Abstand sagt das. Nach
   unten bleibt er darunter, damit die Suchzeile nicht an ihm klebt. */
#seitenlead { margin: 1rem 0 1.5rem; }

/**
 * **Die Ueberschrift waechst mit dem Schirm** (03.09.2026).
 *
 * Vorher stand ueberall 1.8rem - auf dem Telefon richtig, auf einem breiten
 * Schirm zu klein: Der Titel hatte dort dasselbe Gewicht wie eine
 * Abschnittsueberschrift, und eine Seite ohne erkennbaren Anfang liest sich wie
 * eine Fortsetzung.
 *
 * `clamp` statt einer Medienabfrage: Es gibt keinen Punkt, an dem eine
 * Ueberschrift ploetzlich springen soll - sie waechst mit der Breite und hoert
 * bei 2.4rem auf. Der untere Wert ist der alte, auf dem Telefon aendert sich
 * also nichts.
 *
 * Die Eintragsseite hat ihre eigene, groessere Rechnung (`.item-ident h1`):
 * Dort steht der Name mittig und braucht mehr Gewicht, sonst schwimmt er.
 */
/**
 * **Die Ueberschrift muss ein Sprung sein, kein Absatz in fett.**
 *
 * Die Groessen sind angehoben worden, weil eine Seite **ohne Bild** sonst
 * flach liegt: Der Guide daempft seine Ueberschriften mit dem Argument „was
 * gross ist, ist das Bild" - auf „Ueber mich", im Magazin und auf den
 * Prosaseiten gibt es keines, und dann daempft die Regel gegen nichts.
 *
 * Zum Fliesstext (1 rem) steht die h2 damit bei **1,7** statt 1,45 und die h1
 * am unteren Ende bei **2,1** statt 1,8.
 */
h1 {
  color: var(--strong); font-size: clamp(2.1rem, 3.8vw, 2.9rem);
  line-height: 1.2; margin: 0 0 .3rem;
}
/**
 * **Eine Groesse fuer alle Abschnittstitel** (03.09.2026).
 *
 * "Adresse und Kontakt", "Uebernachten in Donaueschingen", "Neu im Guide",
 * "Wonach ist dir?" - das ist ueberall dasselbe: die Gliederung einer langen
 * Seite. Bei 1,05 rem lagen sie kaum ueber der Textgroesse und verschwanden
 * zwischen ihren eigenen Abschnitten.
 *
 * Vorher trug nur die Eintragsseite die groessere Fassung (`#entry > h2`), und
 * die Einstiegsseiten sahen daneben anders aus. Eine Ausnahme fuer eine Seite
 * ist der Anfang von zwei Gestaltungen.
 *
 * Zeilen in Listen sind **keine** Abschnittstitel, auch wenn sie `h2` heissen -
 * `.results h2` bleibt klein.
 */
h2 { color: var(--strong); font-size: var(--fs-h2); margin: 2.6rem 0 .6rem; }
.meta { color: var(--soft); font-size: .88rem; margin: 0; }
.answer h3 { font-size: 1rem; margin: 1.2rem 0 .2rem; }
.results h2 { font-size: 1rem; margin: 0; }
.results h2 a { color: inherit; }

/* Ein Knopf, der wie ein Verweis aussieht: Er aendert die Ansicht, ist aber
   keine Adresse - deshalb button und nicht a. */
.linklike {
  border: none; padding: 0; background: none; color: var(--accent);
  font: inherit; text-decoration: underline; cursor: pointer;
}

/* Foto mit Bildnachweis. Das ⓘ ist ein Knopf und kein Hover-Effekt - auf dem
   Telefon gibt es kein Hover, und der Nachweis muss überall erreichbar sein. */
.photo { position: relative; margin: 1.2rem 0; }
.photo img { display: block; width: 100%; height: auto; background: var(--line); }
/* Unsichtbar, aber vorhanden - fuer Vorleseprogramme und Suchmaschinen.

   `margin: -1px` und `clip-path` gehoeren dazu: `clip` allein ist veraltet und
   laesst in manchen Browsern einen Pixel stehen, der in einem breiten Kasten
   die Seite quer schieben kann. Genau das ist am 03.09.2026 passiert. */
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* Die Gattungen als Eingang. Bewusst ohne Gruppen-Überschriften: Der Gast muss
   die Grenze zwischen Entdecken und Erleben nie verstehen, weil er sie nie sieht.

   **Die zweite `h2`-Regel ist entfallen**: Sie stand hier ein zweites Mal und
   setzte die Groesse wieder auf 1,05 rem - die Einstiegsseiten sahen dadurch
   anders aus als die Eintragsseite, obwohl beide dieselbe Regel meinten. */
.tiles { list-style: none; padding: 0; margin: 0; display: grid; gap: .5rem;
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); }
.tile a, .tile.empty {
  display: flex; flex-direction: column; gap: .1rem;
  border: 1px solid var(--line); padding: .7rem .8rem;
  text-decoration: none; color: inherit; min-height: 4rem;
}
.tile a:hover, .tile a:focus-visible { border-color: var(--accent); }
.tile-label { font-weight: 600; }
.tile-count { color: var(--soft); font-size: .82rem; }
.tile.empty { color: var(--soft); opacity: .55; }

.chipbar { margin: 1rem 0 0; }
.chip {
  border: 1px solid var(--accent); color: var(--accent); background: none;
  padding: .25rem .75rem; font: inherit; font-size: .85rem;
  cursor: pointer;
}

/* Die gemeinsame Form von Eintrag und Veranstaltung: Bild, Pin mit Ort,
   Datum, Karte. Eine CSS-Basis für beide. */
/* Der Ort ist eine Einordnung, keine Überschrift - klein und normal gesetzt.
   Fett trüge er gegen den Namen an, mit dem er in einer Gruppe steht. */
.place {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem 1rem;
  /* **Kein Abstand nach oben** (10.09.2026): Die Ortszeile und der Name
     gehoeren zusammen - sie sagt, **wo** das steht, was er nennt. Auf der
     Eintragsseite steht sie unter der Ueberschrift, auf der Kachel darueber;
     in beiden Faellen liegt dazwischen kein Absatzabstand. */
  margin: 0 0 .25rem; font-size: .85rem; font-weight: 400;
}
/* Zeichen und Text bleiben zusammen - ein Umbruch darf den Pin nicht von
   seinem Ort trennen.

   Der Abstand steht als Merkmal da, weil ihn zwei Regeln brauchen: dieser
   Flex-Abstand und der Punkt vor der Einordnung (siehe `.place-suffix`). Zwei
   Zahlen, die uebereinstimmen muessen, sind eine zu viel. */
.place .where, .place .when, .place .facts {
  --luft: .35rem;
  display: inline-flex; align-items: center; gap: var(--luft);
}
/* Die Kennzahlen eines Weges: je Zahl ein Zeichen, wie bei tirol.at. Ziffern in
   Tabellenbreite, damit "5:10 h" und "14,3 km" nicht wie zwei verschiedene
   Schriften aussehen. */
.facts { font-variant-numeric: tabular-nums; gap: .2rem 1.1rem; }
.fact { display: inline-flex; align-items: center; gap: .3rem; white-space: nowrap; }
/* Etwas groesser als das Pin-Zeichen: Lucide zeichnet in einem 24er Feld mit
   Luft am Rand, ein 0,8-rem-Kasten liess die Zeichen daneben klein wirken. */
.glyph { width: .95rem; height: .95rem; flex: none; color: var(--strong); }
/* Die nicht erreichten Stufen der Schwierigkeitsskala: sichtbar, aber blass -
   ein leerer Platz muss als Platz zu erkennen sein. */
.glyph .dim { opacity: .28; }
/* Auf dem Telefon steht das Datum in einer eigenen Zeile: Neben einem langen
   Ortsnamen bleiben dort keine 250 Pixel, und beides in einer Zeile bricht
   mitten im Zeitraum um. */
@media (max-width: 34rem) {
  .place .when { flex-basis: 100%; }
}
.pin-icon { width: .65rem; height: .8rem; flex: none; stroke: var(--strong); fill: var(--strong); }
/* Die Einordnung hinter dem Ort - Tal oder Region. Kein Verweis: Dazu gibt es
   keine Seite, und ein Link, der nur zur Haelfte stimmt, ist ein falsches
   Versprechen. */
/**
 * Der Punkt sass schief (gefunden am 04.09.2026): Links standen `.35rem`
 * Flex-Abstand **plus** `.4rem` eigener Rand, rechts nur die `.4rem`. Der
 * Flex-Abstand ist fuer Pin und Text gedacht, greift aber auch zwischen Ort und
 * Einordnung - beides zusammen ergab `.75rem` gegen `.4rem`.
 *
 * Jetzt traegt der Punkt nur rechts einen Rand, und zwar genau den Flex-Abstand,
 * den er links ohnehin bekommt. Symmetrisch **von Bauart**, nicht durch zwei
 * Zahlen, die zufaellig passen.
 */
.place-suffix::before {
  content: "·"; margin-right: var(--luft, .35rem); opacity: .55;
}

/* Der Ortsname fuehrt auf die Einstiegsseite des Ortes, wenn es eine gibt.
   Unterstrichen und nicht gefaerbt: Die Zeile ist eine Einordnung, kein Knopf. */
.place .where a { color: inherit; text-decoration: underline; text-underline-offset: .18em; }
.place .where a:hover, .place .where a:focus-visible { color: var(--accent); }
.place time { font-variant-numeric: tabular-nums; }

/**
 * ===========================================================================
 * **List or map** - one switch, not a pair of buttons
 * ===========================================================================
 *
 * The list comes first in the markup - it is the ranking signal, the map is
 * the addition. And these are **two views of the same results**, not two
 * pages: what is chosen here is a state that flips.
 *
 * That is exactly what the shape says. Two equally loud buttons side by side
 * read as "there are two things to press here"; a switch is **one** control
 * with two ends, and the travelling track shows that the subject stays the
 * same while the view changes.
 *
 * **Same track as `.wahlreihe.regler` in the backend - a different thing.**
 * There two radios sit underneath, here two `role="tab"` buttons and two
 * views. That is why the shape is written out a second time instead of
 * sharing a selector list: the looks are the same, the controls are not, and
 * one selector across both would promise that a change to either is right for
 * the other.
 *
 * **The round ends are not a new exception** to `border-radius: 0` - they are
 * number 8 of the list in the style guide ("Eckig - und seine Ausnahmen"): a
 * track has ends, not corners.
 *
 * **There is no border - the rail is a filled surface** (`--shade`). With a
 * black outline the bar carried two blacks on 38 pixels, and the travelling
 * track ran along an edge as heavy as itself: one read the box before the
 * state. A grey ground says the same and steps back.
 *
 * **It measures 33 pixels** and is thereby **smaller than the row of category
 * pills above it** (36). That is the order of the two questions on this page:
 * which category is the loud one, which view the quiet one. As long as the
 * switch was the taller of the two, it claimed the opposite.
 *
 * The padding is the one the backend switch uses (`.32rem 1rem`); only the
 * type is a notch larger (`.9rem` against `.8rem`), because out here it is
 * read at arm's length and not in a dense editor row.
 *
 * **The price, stated:** 38 is below the 44 pixels a thumb wants. The whole
 * half is the target, so it is 93 by 38 rather than a small square - but it
 * is under the recommendation, and that is a choice, not an oversight.
 * =========================================================================== */
/* Aligned right: a setting of the view, not a heading. `width: fit-content`
   plus `margin-inline-start: auto` - a block-level grid box, because `auto`
   does not resolve on an inline box. */
/**
 * **Die Schiene ist eine Flaeche, kein Rahmen.**
 *
 * Sie hatte einen schwarzen Strich ringsum und darin eine schwarze Spur - zwei
 * Schwarz auf einer Bahn von 38 Pixeln, und die Spur lief an einer Kante
 * entlang, die genauso schwer war wie sie. Ein grauer Grund (`--shade`,
 * dieselbe Flaeche, die im Haus „leise gefuellt" heisst) traegt dasselbe und
 * tritt zurueck: Man sieht, **welche Haelfte gewaehlt ist**, statt zuerst den
 * Kasten.
 *
 * Zwei Pixel Polster bleiben - sie sind der Abstand der Spur zur Kante, und
 * ohne sie saesse sie auf ihr.
 */
.viewtabs {
  position: relative;
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 0;
  width: fit-content; margin: 0 0 1.4rem; margin-inline-start: auto;
  min-height: var(--regler-hoehe); padding: 2px;
  border: 0; border-radius: 999px; background: var(--shade);
}
/* Die fahrende Spur: eine Haelfte breit, beim Umschalten laeuft sie hinueber.
   Sie sitzt zwei Pixel innerhalb der Bahn, damit die runde Kante ringsum ganz
   bleibt - eine Spur **in** einer Schiene, keine Pille darauf. */
.viewtabs::before {
  content: ""; position: absolute; z-index: 0; top: 2px; bottom: 2px; left: 2px;
  width: calc(50% - 2px); border-radius: 999px;
  background: var(--strong); transition: transform .18s ease;
}
.viewtabs:has(button:last-child[aria-selected="true"])::before {
  transform: translateX(100%);
}
@media (prefers-reduced-motion: reduce) {
  .viewtabs::before { transition: none; }
}
.viewtabs button {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: .45rem;
  /* Die **nicht** gewaehlte Haelfte steht leise auf der grauen Bahn - schwarz
     waeren beide gleich laut, und der Umschalter saehe aus wie zwei Knoepfe. */
  border: 0; border-radius: 999px; background: none; color: var(--soft);
  padding: .26rem .85rem; font: inherit; font-size: .82rem; cursor: pointer;
  transition: color .18s ease;
}
.viewtabs .nav-icon { width: .95rem; height: .95rem; flex: none; }
/* The chosen state is the track underneath - the button carries only the
   words. A second filled box on top of it would show its edge while moving. */
.viewtabs button[aria-selected="true"] { color: var(--paper); }
/* The ring belongs around the whole control: what gets hit is a switch, not
   one of its halves. */
.viewtabs:has(button:focus-visible) { outline: 2px solid var(--strong); outline-offset: 2px; }
.viewtabs button:focus-visible { outline: none; }
/* Forced colors replace every background - the track disappears, and without
   this line nothing says which view applies. */
@media (forced-colors: active) {
  .viewtabs button[aria-selected="true"] { outline: 2px solid; outline-offset: -4px; }
}

.results li.active:not(:has(.card)) {
  background: color-mix(in srgb, var(--accent) 7%, transparent);
}

/* "Neu im Guide" - die Form aus der Vorlage: Bild mit Titel darauf, darunter
   Pin und Ort, kurze Punkte, Karte rechts. */
/* "Neu im Guide": ab 62rem zwei Kacheln nebeneinander.
   Der Grund ist das Bild - über die vollen 1100 Pixel wäre ein 3:2-Foto 733
   Pixel hoch und nähme fast einen Bildschirm ein. Nebeneinander sind es 530 zu
   353, und zwei Kacheln passen in einen Blick. */
/**
 * ===========================================================================
 * **DER PLATZ FUER „JETZT OFFEN" UND DAS WETTER**
 * ===========================================================================
 *
 * `#entry-jetzt` ist der Anker unter der Ortszeile einer **gebauten**
 * Eintrags- oder Veranstaltungsseite. Er ist leer, bis die Insel ihn fuellt
 * (`entry.js andocken`) - und beides haengt an der **Uhr**, also darf es nicht
 * gebaut werden: „Ist geoeffnet" auf einer Seite, die um 23 Uhr ausgeliefert
 * wurde, waere eine Behauptung.
 *
 * Also haelt der Anker **vorher den Platz frei, den der Inhalt danach nimmt** -
 * gemessen am fertigen Anker (Hoehe des Ankers samt den Raendern der Zeilen
 * darin, die nicht aus ihm herausfallen), nicht an der Zeile allein:
 *
 * | Inhalt | gemessen | Marke |
 * |---|---|---|
 * | nur das Wetter | 28,0 px | – |
 * | Tuerzustand und Wetter | 50,7 px | `jetzt-zwei` |
 * | „Immer zugaenglich" und Wetter, unter 27 rem | 71,7 px | `jetzt-immer` |
 *
 * **Die Zeile allein misst 24,8 px, der Anker 28** - der obere Rand der
 * Wetterzeile bleibt im Anker. Mit der Zeilenhoehe als Mass sprang alles
 * darunter um 3,2 px, auf jeder Seite ohne Tuerzustand und auch mit dem Wert
 * aus dem Zwischenspeicher.
 *
 * **Die Marken setzt der Bau** (`Eintragsseite.astro`): Er weiss, ob es einen
 * frischen Tuerzustand gibt (`BFP.hoursFresh`, dieselbe Frist wie die Insel).
 * „Immer zugaenglich · frei zugaenglich, keine Oeffnungszeiten" bricht unter
 * gemessenen 420 px in zwei Zeilen um (Deutsch und Englisch, Franzoesisch
 * unter 370); 27 rem laesst etwas Luft. Dazwischen bleibt eine Luecke, kein
 * Sprung.
 *
 * **Warum `min-height` und nicht `height`:** Bricht eine Zeile doch einmal
 * um, schnitte eine feste Hoehe sie ab; `min-height` haelt den Platz und gibt
 * nach.
 */
#entry-jetzt { min-height: 1.75rem; }

/**
 * **Der Platz fuer die Ueberschrift der Anwendungshuelle** (08.09.2026).
 *
 * `#pagetitle` steht in `web/suche.html` leer und wird von `app.js` gefuellt -
 * die Seite sprang deshalb beim Laden um eine Zeilenhoehe. Sie ist die einzige
 * Seitenart, die nicht gebaut wird (reine Anwendung, `noindex`), also gibt es
 * hier nichts zu bauen; es gibt nur Platz zu halten.
 *
 * Auf einer **gebauten** Ergebnisseite steht die Ueberschrift von Anfang an im
 * Dokument - dort tut die Regel nichts, weil der Inhalt hoeher ist als das
 * Mindestmass.
 */
#pagetitle { min-height: 2.6rem; }
#entry-jetzt.jetzt-zwei { min-height: 3.17rem; }
@media (max-width: 27rem) {
  #entry-jetzt.jetzt-immer { min-height: 4.48rem; }
}

/* **Eins oder zwei** - Telefon, dann alles darueber.
   Die zweite Spalte beginnt bei 48 rem (768 px, ein Tablet im Hochformat) und
   nicht erst bei 62: Dazwischen stuende eine Kachel allein auf einem Schirm,
   auf den zwei passen.

   **Die dritte steht ab 84 rem** - und dort wird der Rahmen im selben Atemzug
   breiter (`--rahmen-breite`, siehe oben). Die zwei gehoeren zusammen: Am
   1100er Rahmen waere die dritte Kachel 332 px breit und ihr Foto 302, am
   1280er sind es 392 und 357. Was beim Aufteilen schrumpft, ist das **Bild**,
   und eine Kachel lebt von der Aufnahme - deshalb faengt die dritte Spalte
   erst dort an, wo Platz fuer sie ist, statt den vorhandenen feiner zu
   schneiden.

   Dieselben Zahlen gelten fuer die Startseite, die Trefferliste und die
   Ortsseite: Eine Kachelliste, die je Flaeche anders bricht, ist dieselbe
   Liste in drei Gestalten. */
#neu, .results:has(.card), .ort-kacheln { display: grid; gap: 2.4rem 2rem; }
@media (min-width: 48rem) {
  #neu, .results:has(.card), .ort-kacheln { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 84rem) {
  #neu, .results:has(.card), .ort-kacheln { grid-template-columns: 1fr 1fr 1fr; }
}
/**
 * ===========================================================================
 * **DIE KACHEL IST FLACH** - Foto, Name, eine Fusszeile
 * ===========================================================================
 *
 * Kein Papier, kein Schatten, kein Rahmen: Die Kachel ist die Regel des
 * Hauses und keine Ausnahme mehr. Was sie zusammenhaelt, ist das **Foto** -
 * es steht oben, in voller Breite, und der Text darunter liegt an seiner
 * linken Kante. Getrennt werden zwei Kacheln vom Abstand des Rasters
 * (`gap: 2.4rem 2rem`), nicht von einer Kante.
 *
 * **Sie faerbt sich nicht mehr selbst hell.** Ein Abzug kannte kein Hell und
 * Dunkel und setzte deshalb alle Farbtoken auf ihre hellen Werte zurueck.
 * Eine flache Kachel steht auf dem Papier der Seite - also liest sie die
 * Token der Seite, und der Dunkelmodus trifft sie wie alles andere.
 *
 * **Auf dem Foto steht nichts** ausser dem Bildnachweis. Die Gattung stand
 * dort als Etikett; sie beantwortet eine Frage, die der Filter, der auf diese
 * Liste gefuehrt hat, schon beantwortet hat - und auf der Eintragsseite steht
 * sie vollstaendig.
 *
 * **Die Kachel ist eine Spalte mit einem Fuss.** `flex-direction: column` und
 * `margin-top: auto` an der Fusszeile: So steht „Mehr erfahren" bei allen
 * Kacheln einer Reihe auf einer Linie, auch wenn ein Name umbricht und der
 * daneben nicht. Dafuer bleibt `height: 100%` - ohne sie ist die Kachel nur
 * so hoch wie ihr Inhalt, und es gaebe keinen Platz, den der Fuss ausfuellen
 * koennte.
 */
.card {
  margin-bottom: 0;
  position: relative;
  display: flex; flex-direction: column;
  height: 100%;
  color: var(--ink);
}
/* **Kein Anheben, kein Schatten.** Beides gehoerte dem Abzug. Der Zustand
   steht da, wo er im Haus immer steht: im Wort - der Name faerbt sich, und
   „Mehr erfahren" unterstreicht sich. `focus-within` ist kein Zusatz, sondern
   die Haelfte fuer die Tastatur: Der Titel darin ist ein Verweis. */
.card:hover .card-more > span,
.card:focus-within .card-more > span { text-decoration: underline; }
/**
 * **Das Bildfeld ist ein Raster aus vier Feldern** - und drei davon sind leer.
 *
 * Das Foto liegt ueber allen vieren, das Namensetikett unten links, und unten
 * rechts steht ein **Quadrat**, das nichts enthaelt: der Ausschnitt Foto, der
 * neben dem Etikett stehen bleibt. Es ist gerechnet und nicht gesetzt -
 * `aspect-ratio: 1` in einem Feld, dessen Hoehe die Zeile des Etiketts vorgibt.
 * Die Spalte daneben ist `1fr`, also nimmt das Etikett **immer den Rest**: Es
 * ist bei einem kurzen Namen genauso breit wie bei einem langen, und was frei
 * bleibt, ist in jedem Fall dasselbe Quadrat. Bei zwei Zeilen waechst beides
 * mit.
 *
 * **Nicht `position: absolute`, und das ist der Punkt:** Ein positioniertes
 * Element waere der Bezug fuer das `::after` des Titels - und genau das muss
 * gegen die **ganze Kachel** rechnen, sonst ist nur noch das Etikett anklickbar
 * und nicht mehr die Kachel. Ein Raster kostet diesen Bezug nicht.
 *
 * Wer oben liegt, entscheidet die Reihenfolge im Dokument: Das Etikett steht
 * nach dem Foto, also malt es darueber - ohne `z-index`.
 */
.card-visual {
  /* **Nicht positioniert**, und das ist die Bedingung dafuer, dass die ganze
     Kachel anklickbar bleibt: Das `::after` des Titels liegt darin und rechnet
     gegen den naechsten **positionierten** Vorfahren. Waere das hier, deckte
     es nur das Bild ab und die Fusszeile darunter waere tot. So ist es `.card`.
     Der Bildnachweis verliert nichts - er rechnet dann ebenfalls gegen `.card`,
     und deren obere rechte Ecke ist die des Fotos. */
  display: grid; grid-template-columns: 1fr auto; grid-template-rows: 1fr auto;
}
/* Das Foto - und die Flaeche ohne Bild - liegen ueber allen vier Feldern. */
.card-visual > :not(.card-title) { grid-area: 1 / 1 / -1 / -1; }
/**
 * Das Quadrat: leer, ohne Grund, nur ein Platzhalter mit einer Breite.
 *
 * **`--card-eck` ist gerechnet, nicht gegriffen** - es ist genau die Hoehe
 * eines einzeiligen Etiketts: `1.2rem * 1.25` Zeile plus `.55rem + .5rem`
 * Innenabstand. Damit ist der freie Ausschnitt bei einem einzeiligen Namen ein
 * **Quadrat**; bei zwei Zeilen bleibt er gleich breit und wird hoeher.
 *
 * **Warum eine Zahl und nicht `aspect-ratio: 1`:** Die Fusszeile unter dem
 * Bild soll rechts mit der Kante des Etiketts abschliessen, und sie steht in
 * einem anderen Element - sie kann die Hoehe des Etiketts nicht lesen. Ein
 * Wert, den beide kennen, ist der einzige Weg zu einer Kante, die wirklich
 * eine ist.
 */
.card { --card-eck: calc(1.2rem * 1.25 + 1.05rem); }
.card-visual::after { content: ""; grid-area: 2 / 2; width: var(--card-eck); }
.card-visual img { display: block; width: 100%; height: auto; }
/* **Die Kachel ohne Bild** - eine Auskunft, kein graues Rechteck.

   Hoehenlinien auf Schwarz: Das Muster ist Marke, und seine Linien sind weiss
   mit 15 Prozent Deckung (siehe Kopf dieser Datei) - sie brauchen den dunklen
   Grund, sonst sieht man sie nicht. Deshalb stehen hier feste Werte und keine
   Tokens: Die Flaeche ist in beiden Erscheinungsbildern dieselbe, genau wie das
   Etikett und der Titel, die darauf liegen.

   Der Innenabstand ist oben und unten groesser als seitlich und **oben wie
   unten gleich**: Auf dem Bild liegt nur noch das Etikett der Gattung, und
   Baum und Spruch stehen mittig in der Flaeche. Ein groesserer Wert unten
   schoebe sie sichtbar nach oben. */
.card-noimage {
  aspect-ratio: 16 / 9;
  background-color: #000;
  background-image: url("hoehenlinien.svg");
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  gap: .5rem;
  padding: 2.4rem 1.2rem;
  text-align: center;
  color: #fff;
}
/* **Der Baum steht ueber dem Text, im selben Grauton.**

   Die Farbe wird auf dem Zeichen gesetzt und nicht geerbt, damit sie
   nachweislich dieselbe ist wie die der Zeile darunter - zwei getippte
   rgba-Werte waeren zwei Werte, die auseinandergehen. Deshalb steht der Ton
   einmal als Variable auf dem Kasten und wird von beiden benutzt. */
/* Gray 600 aus dem Styleguide, als **fester Wert** und nicht als `var(--soft)`.
   Der Grund ist derselbe wie beim Bildnachweis (siehe Kopf dieser Datei): Die
   Flaeche ist immer dunkel, in beiden Erscheinungsbildern. Ein Token, das im
   Dunkelmodus mitzieht, wuerde hier in die falsche Richtung zeigen. */
.card-noimage { --noimage-ink: #6c757d; }
/**
 * **Auf der Eintragsseite ein Drittel hoch** (04.09.2026).
 *
 * Dieselbe Flaeche, dasselbe Muster, derselbe Weg zum Beitragen - nur flach:
 * 48:9 statt 16:9 ist genau ein Drittel der Hoehe bei gleicher Breite. Auf
 * einer Kachel bleibt sie hoch, denn dort **ist** sie das Bild; auf der
 * Eintragsseite ist sie eine Randbemerkung, und eine Randbemerkung nimmt nicht
 * den halben Bildschirm.
 *
 * Der Innenabstand faellt mit: 2,4 rem oben in einer Flaeche von 130 Pixeln
 * waere kein Abstand, sondern der ganze Inhalt.
 */
.card-noimage-flach {
  /**
   * **Die Breite kommt vom Rahmen, nie aus der Hoehe.**
   *
   * `aspect-ratio` und `min-height` zusammen sind eine Falle: Die Flaeche
   * steht in einem Raster, das seine Kinder mittig stellt
   * (`.item-ident`-Bauart), also ist ihre Breite ohne Angabe *schrumpfend*.
   * Unterschreitet die Hoehe aus dem Verhaeltnis die 7 rem, gewinnt
   * `min-height` - und der Browser rechnet die Breite aus der neuen Hoehe
   * zurueck: 112 px mal 48/9 sind **597 px**. Auf einem Telefon von 390 stand
   * die Flaeche damit 144 px ueber dem Rand, und die Eintragsseite hatte
   * einen waagerechten Rollbalken. **Der Fehler ist lautlos** - die Flaeche
   * sieht richtig aus, man sieht nur den Balken unten.
   *
   * `width: 100%` dreht die Richtung um: Die Breite ist der Rahmen, das
   * Verhaeltnis gibt die Hoehe, und `min-height` macht sie nur noch hoeher.
   */
  width: 100%;
  aspect-ratio: 48 / 9;
  /* Bei sehr schmalen Schirmen sonst nur noch ein Streifen. */
  min-height: 7rem;
  padding: 1rem 1.2rem;
  gap: .35rem;
}
/* **Groesser als beim ersten Versuch** (04.09.2026): 1,4 rem war ein Zeichen
   neben einem Satz; auf einer Flaeche, die sonst leer ist, ist der Baum die
   Sache. 2,2 rem in einer Flaeche von 130 Pixeln lassen ihn wirken, ohne dass
   er den Spruch verdraengt. */
.card-noimage-flach .card-noimage-tree { width: 2.2rem; height: auto; }
.card-noimage-tree {
  width: 2.8rem; height: 3.4rem; flex: none;
  color: var(--noimage-ink);
  /* Etwas Luft nach unten, aber weniger als zwischen Text und Aufruf: Zeichen
     und Satz gehoeren zusammen, der Aufruf ist der naechste Gedanke. */
  margin-bottom: -.1rem;
}
/* Der Kasten steht mit im Selektor, und zwar mit Grund: `.results p` faerbt
   jeden Absatz in einer Ergebnisliste grau (`--soft`) und gewinnt mit 0-1-1
   gegen eine einzelne Klasse. Zwei Klassen sind 0-2-0 und damit staerker -
   ein `!important` waere die faule Loesung und der naechste, der hier etwas
   aendern will, kaeme daran nicht vorbei. */
.card-noimage .card-noimage-line {
  margin: 0;
  font-size: .88rem; line-height: 1.4;
  color: var(--noimage-ink);
  /* Zwei Zeilen reichen; laenger wird die Kachel unruhig. */
  max-width: 22rem;
}
/* Halbfett, nicht fett: Der Aufruf steht auf fast jeder Kachel ohne Bild - bei
   197 von 199 Eintraegen ohne Primärbild ist das die Regel und nicht die
   Ausnahme. In Fett gesetzt liest sich eine Ergebnisliste wie eine Wand aus
   Bitten. */
/* Der Aufruf unter dem Spruch ist weg (04.09.2026) - `.card-noimage-cta` mit
   ihm: Bilder kommen ueber eine Einladung herein, nicht ueber einen Knopf auf
   einer leeren Flaeche. */
/* Auf sehr schmalen Kacheln bleibt nur der Aufruf - der Scherz davor ist das
   Erste, was weichen darf. */
@media (max-width: 26rem) {
  .card-noimage .card-noimage-line { display: none; }
  /* Das Zeichen bleibt - es kostet keine Zeile und traegt die Marke. */
  .card-noimage-tree { width: 2.3rem; height: 2.8rem; }
}
/* **Auf dem Foto steht ein Kasten, nicht zwei** - der Bildnachweis, oben
   rechts. Das Etikett der Gattung stand links daneben; es beantwortete eine
   Frage, die der Weg auf diese Liste schon beantwortet hat, und auf der
   Eintragsseite steht die Gattung vollstaendig statt auf zwei Woerter
   gekuerzt. */
/**
 * **Der Titel steht unter dem Foto, auf Papier.**
 *
 * Er braucht damit keinen eigenen Grund und keine festen Farben mehr - was auf
 * einem Foto liegt, muss in hell und dunkel gleich lesbar sein, was auf Papier
 * liegt, nimmt die Token des Hauses.
 *
 * **Er steht unter der Ortszeile** und ist der eine Halt in der
 * Tabulatorreihenfolge der Kachel: Das Bild fuehrt an dieselbe Adresse und ist
 * fuer ein Vorleseprogramm stumm.
 *
 * **Der senkrechte Innenabstand ist die Trefferflaeche**, nicht Zierde: Als
 * blosse Zeile waere der Verweis 24 Pixel hoch, und zehn Pixel darueber liegt
 * der Ortsname als zweites kleines Ziel. Mit `.5rem` oben und unten kommt er
 * auf die 44 Pixel, die ein Daumen braucht - deshalb `display: block`, sonst
 * traegt der Innenabstand nichts.
 */
/**
 * **Das Etikett: unten links im Bild, so breit wie der Platz neben dem
 * Quadrat.**
 *
 * Es sitzt im Feld unten links (`2 / 1`) und fuellt es - die Spalte ist `1fr`,
 * also die ganze Breite ohne das Quadrat rechts. **Deshalb ist es bei einem
 * kurzen Namen genauso breit wie bei einem langen:** Was neben ihm frei
 * bleibt, ist eine Eigenschaft der Kachel und nicht des Namens. Zweizeilig
 * waechst es nach **oben**; der Name steht in jedem Fall im Bild.
 *
 * **Links buendig, ohne Blitzer:** kein Rand, kein Abstand, keine runde Ecke -
 * die Flaeche sitzt auf der Kante des Fotos. Eingerueckt ist nur der **Text**,
 * ueber den Innenabstand.
 *
 * **`--paper` und kein Weiss**, damit die Kachel im Dunkelmodus mitgeht.
 */
.card-title {
  grid-area: 2 / 1;
  background: var(--paper);
  margin: 0; padding: .55rem var(--inset) .5rem;
  color: var(--strong); text-decoration: none;
  /* **Normal gesetzt, nicht fett.** Der Name ist die eine Aussage der Kachel;
     in einer Liste aus zwoelf fetten Zeilen ist keine mehr hervorgehoben. Das
     Gewicht traegt stattdessen die Groesse - 1,2 rem gegen die 0,85 rem der
     Fusszeile darunter. */
  font-size: 1.2rem; font-weight: 400; line-height: 1.25;
}
.card-title:hover, .card-title:focus-visible { color: var(--accent); }
/* **On the phone every card title steps down to 1 rem** - start page, result
   list, place page, magazine. Below 48 rem the grid is one column, and at
   1.2 rem a name takes more lines over the photo than a narrow screen can
   spare. The corner square follows the new line height (`--card-eck` is the
   height of a one-line label), otherwise the free square would stay taller
   than the label. */
@media (max-width: 47.99rem) {
  .card { --card-eck: calc(1rem * 1.25 + 1.05rem); }
  .card-title { font-size: 1rem; }
}
/**
 * **Die ganze Kachel ist der Verweis** - gedeckt vom `::after` des Titels.
 *
 * Ein `<a>` um alles herum ginge nicht: Im Foto sitzt mit dem Bildnachweis ein
 * **Knopf**, und ein Knopf in einem Verweis ist ungueltiges Markup. Die
 * gestreckte Flaeche loest beides: ein Verweis im Dokument, eine Haltestelle
 * in der Tabulatorreihenfolge, und die Trefferflaeche ist die Kachel.
 *
 * `inset: 0` rechnet gegen die Kachel, weil die schon `position: relative`
 * traegt (fuer das Anheben unter der Maus). Ohne diese Zeile griffe es auf das
 * naechste positionierte Elternteil - und das waere irgendwo auf der Seite.
 */
.card-title::after { content: ""; position: absolute; inset: 0; }
/**
 * **Und das ⓘ liegt darueber.** Es steht im Markup **vor** dem Titel, also
 * malt die Deckflaeche darueber - ohne diese Zeile waere der Bildnachweis ein
 * Knopf, den man sieht und nicht mehr trifft. Er ist ohnehin positioniert, es
 * fehlt nur die Ebene.
 */
.card .credit-chip { z-index: 2; }
/* Die Kennzahlenzeile sitzt direkt am Namen: Den Abstand dazwischen gibt der
   Innenabstand des Titels, nicht zusaetzlich der Rand des Absatzes. */
.card-main .place { margin-bottom: 0; }
/**
 * ===========================================================================
 * **DIE FUSSZEILE DER KACHEL** - wo und wann links, der Weg weiter rechts
 * ===========================================================================
 *
 * Sie ist eine `.place` und erbt damit Pin, Kalender, Schriftgroesse und den
 * Umbruch auf dem Telefon. Was dazukommt, sind zwei Zeilen: Sie wird nach
 * unten geschoben, und das Wort rechts nimmt den Rest der Breite.
 *
 * **`margin-top: auto` statt einer festen Hoehe.** Die Kachel ist eine Spalte
 * (`.card`, `flex-direction: column`), also faellt der Ueberschuss der
 * Fusszeile zu - und „Mehr erfahren" steht bei allen Kacheln einer Reihe auf
 * einer Linie, auch wenn ein Name zwei Zeilen braucht und der daneben eine.
 *
 * **`margin-left: auto` und nicht `justify-content: space-between`.** Ohne
 * Ort und ohne Datum hat die Zeile nur ein Kind, und `space-between` setzte es
 * dann nach **links** - genau in dem Fall, in dem es allein steht und rechts
 * stehen soll. Der eigene Rand kennt seine Nachbarn nicht und ist deshalb in
 * beiden Faellen richtig.
 */
.card-foot {
  margin-top: auto; padding-top: .55rem;
  /* Die Kette der Hoehen: Die Kachel ist eine Spalte, ihr Rumpf muss eine
     sein, sonst steht der Fuss am Text und nicht am Boden. */
}
.card .card-main { flex: 1; }
.card .item-body { display: flex; flex-direction: column; height: 100%; }
/**
 * **Unter dem Bild steht nur die Fusszeile** - auf dem Papier der Seite, ohne
 * eigene Flaeche.
 *
 * Links steht ihr Text auf derselben Senkrechten wie der Name im Etikett
 * darueber (`--inset`), rechts endet sie auf dessen Kante (`--card-eck`):
 * Zwei Textkanten in einer Kachel waeren eine zu viel, und „Mehr erfahren"
 * soll unter dem Etikett stehen und nicht daneben.
 */
/* **Kein Abstand nach oben:** Das Etikett bringt seinen eigenen Innenabstand
   mit, und die Fusszeile steht direkt darunter - zwei Luecken uebereinander
   liessen den Text von seiner Kachel abrutschen. */
.card .card-main { padding: 0 var(--card-eck) 0 var(--inset); }
/**
 * **Wo und wann stehen untereinander** - eine Veranstaltung hat beides, und
 * nebeneinander stuenden sie mit „Mehr erfahren" zu dritt in einer Zeile.
 *
 * `min-width: 0`, sonst laeuft die Zeile ueber die Kante: Ein Flex-Kind ist
 * von sich aus so breit wie sein laengster unteilbarer Inhalt, und
 * „St. Blasien · Hochschwarzwald" plus „Mehr erfahren" ist auf einem Telefon
 * breiter als die Kachel. Mit 0 als Mindestbreite darf die linke Haelfte
 * schrumpfen und ihr Text umbrechen - das Wort rechts bleibt, wo es hingehoert.
 *
 * `flex-basis: auto` hebt die Telefonregel der Ortszeile auf: Dort schickt
 * `.place .when { flex-basis: 100% }` das Datum in eine eigene Zeile - in
 * einer **Spalte** ist `flex-basis` die Hoehe, und 100 % davon waere die ganze
 * Zeile fuer das Datum allein.
 */
.card-wo {
  display: flex; flex-direction: column; gap: .15rem; min-width: 0;
  /* **Where and when are grey, the way on is black.** The left half is the
     classification of the card, "Mehr erfahren" the action - in the same ink
     they read as two equal statements. */
  color: var(--soft);
}
/* Pin and calendar carry `--strong` from their own rules (`.pin-icon`,
   `.cal-icon`), so they are handed the grey explicitly. */
.card-wo .pin-icon { stroke: currentColor; fill: currentColor; }
.card-wo .cal-icon { stroke: currentColor; }
.card-wo .when { flex-basis: auto; }
/* **Normal gesetzt wie der Name darueber.** Fett waere eine zweite Betonung in
   einer Kachel, die schon eine hat - und „Mehr erfahren" ist der Weg hinaus,
   nicht die Aussage. Das Zeichen dahinter ist der Pfeil der Navigation
   (`.nav-icon`), also braucht es hier keine eigene Groesse. */
.card-more {
  margin-left: auto;
  display: inline-flex; align-items: center; gap: .3rem;
  white-space: nowrap; font-weight: 400; color: var(--strong);
  /* Es ist kein Verweis (die Kachel ist einer), sieht aber aus wie einer -
     also zeigt der Zeiger, was ein Klick tut. */
  cursor: pointer;
}
/* Text und Karte stehen nebeneinander - auch auf dem Telefon. Gestapelt waere
   die Karte unter dem Text gelandet, wo sie niemand sucht; als Randspalte
   beantwortet sie "wo ist das" im Vorbeisehen.

   Begrenzt wird sie ueber die **Hoehe**, nicht ueber die Breite: Die
   Schwarzwald-Kontur ist hochkant (146 zu 240). Ein Drittel Breite hiess auf dem
   Desktop 340 Pixel breit und damit 558 hoch - die Karte war hoeher als der
   ganze Text daneben. Die Spalte nimmt deshalb, was die Karte braucht, und der
   Text bekommt den Rest. */
/* Die Aufteilung gilt fuer **Kachel und Eintragsseite**: Auf der Eintragsseite
   stand die Karte vorher unter dem Text und damit ausserhalb des Blickfelds.
   Eine Klasse fuer beide - sonst haetten wir zwei Karten mit zwei Verhalten. */
.item-main { display: grid; grid-template-columns: 1fr auto; gap: 1.2rem; }
/* **Ohne Karte kein zweispaltiges Raster.** Die leere zweite Spalte kostete
   nichts, ihre Luecke aber schon: Der Text stand um die halbe Luecke (10 Pixel)
   links der Mitte, waehrend alles darueber und darunter mittig sass. Solche
   Verschiebungen sieht man nicht, man spuert sie nur. */
.item-main:not(:has(.map)) { grid-template-columns: 1fr; gap: 0; }
.item-main .map { margin: 0; }
/* **Den Einzug gibt der weisse Rand des Abzugs**, nicht der Textblock: Sein
   linker Rand ist die Kante des Fotos darueber, und darauf stehen Ortszeile,
   Titel und Kennzahlen. Auf der Eintragsseite sitzt der Text ohnehin schon in
   seiner Spalte. */
.card-main { padding: .6rem 0 0; }
/**
 * **Auf der Kachel steht kein Satz.**
 *
 * `description` ist der Fliesstext der Eintragsseite und - auf 155 Zeichen
 * geschnitten - die Meta-Description. Die Kachel beantwortet „was ist das, wo
 * ist es"; der Grund hinzugehen steht auf der Seite dahinter, einen Klick
 * entfernt. Ohne den Satz sind die Kacheln einer Reihe gleich hoch, und die
 * Reihe behaelt eine Linie.
 *
 * Aus demselben Grund gibt es hier keine Stichpunkte: `.card` zeichnet weder
 * `.lead` noch eine Liste.
 */
/* Untergrenze angehoben: Auf dem Telefon war die Karte zu klein, um die Lage
   noch zu lesen. Der vw-Anteil greift dadurch erst im Tabletbereich - unten und
   oben regieren die Grenzen. */
.item-main .map svg { height: clamp(11rem, 26vw, 13.5rem); width: auto; }
@media (min-width: 62rem) { .card-main .map svg { height: 11.5rem; } }
/* Auf der Eintragsseite ist mehr Platz als in einer Kachel - dort darf die
   Karte groesser stehen. */
@media (min-width: 62rem) { .item-main:not(.card-main) .map svg { height: 15rem; } }
.cal-icon { width: .8rem; height: .8rem; flex: none; stroke: var(--strong); }
/* Die Kacheln sind Querformat, viele Fotos nicht. In der Kachel wird deshalb auf
   3:2 beschnitten - steuerbar über object-position, damit der Ausschnitt nicht
   das Motiv wegschneidet. Auf der Eintragsseite steht das ganze Bild. */
.card-visual img { aspect-ratio: 3 / 2; object-fit: cover; }
/**
 * **Nicht die flache Fassung** (04.09.2026).
 *
 * Diese Zeile stand 150 Zeilen **nach** `.card-noimage-flach` und hat sie
 * ueberschrieben - gleiche Spezifitaet, spaeter im Blatt, also gewinnt sie.
 * Die Flaeche auf der Eintragsseite blieb dadurch hoch, obwohl die flache
 * Regel danebenstand und richtig war. Ein Fehler, den man nicht sieht, indem
 * man die neue Regel ansieht: Sie ist ja da.
 *
 * `:not()` statt einer noch spaeteren Regel: So sagt die Zeile selbst, dass es
 * eine Ausnahme gibt, statt sie hinter sich zu verstecken.
 */
.card-noimage:not(.card-noimage-flach) { aspect-ratio: 3 / 2; }

/* Der Nachweis liegt AUF dem Foto und klappt beim Klick auf das ⓘ auf.
   Überall Querformat: die Formen sind es, viele Fotos nicht. */
.photo img { aspect-ratio: 3 / 2; object-fit: cover; }
/**
 * **In der Kachel ist das Foto nicht positioniert** - und das ist keine
 * Feinheit, sondern die Bedingung dafuer, dass der Name darauf zu sehen ist.
 *
 * `.photo` traegt sonst `position: relative` (fuer den Bildnachweis darin), und
 * ein positioniertes Element malt ueber jedes **statische** Geschwister -
 * gleichgueltig, was im Dokument spaeter steht. Das Etikett verschwand damit
 * unter dem Bild, ohne dass etwas fehlte.
 *
 * **Der Bildnachweis verliert dadurch nichts:** Er ist absolut gesetzt und
 * rechnet jetzt gegen `.card-visual` statt gegen `.photo` - und die zwei
 * liegen genau uebereinander, weil das Foto das Feld fuellt.
 */
.card-visual .photo { margin: 0; position: static; }


/* Der Nachweis klappt aus dem Kreis heraus: eingeklappt ist das ⓘ ein Kreis,
   ausgeklappt wird daraus eine Zeile. Geschaltet wird ein Zustand, die Bewegung
   macht CSS - und der Text steht immer im Dokument, auch eingeklappt, damit ein
   Vorleseprogramm die Namensnennung in jedem Fall liest.

   Weißer Grund, schwarzer Kreis, das i mittig darin. Feste Farben und keine
   Variablen: Das Zeichen liegt auf einem Foto und muss dort in beiden
   Erscheinungsbildern lesbar bleiben - ein helles i auf einem hellen Himmel
   wäre unsichtbar. */
.photo .credit-chip {
  /* **Oben** rechts, nicht unten. Unten sass er neben dem Titel, und beide
     teilten sich eine Kante: Ein langer Titel und ein aufgeklappter Nachweis
     trafen sich zwangslaeufig - erst bei "Donaueschinger Musiktage" sichtbar,
     aber angelegt war es vorher. Oben rechts kann das nie passieren, bei keiner
     Titellaenge. Der Nachweis gehoert zum Bild, der Titel zum Eintrag. */
  /* Der Abstand zum Bildrand bleibt, wie er war - kleiner geworden ist nur das
     Zeichen selbst, und damit waechst der Abstand von innen. */
  position: absolute; right: .6rem; top: .6rem;
  display: flex; align-items: center; max-width: calc(100% - 1.2rem);
  background: var(--credit-grund); color: var(--credit-ink);
  padding: .15rem; box-shadow: 0 1px 4px rgba(0, 0, 0, .25);
  /* Rund - und das ist die Ausnahme, die der Styleguide selbst nennt:
     Rundungen gibt es, wo die Form selbst rund ist. Eingeklappt IST dieser
     Grund der Kreis um das i; eckig würde daraus ein Kasten mit einem Kreis
     darin. Ausgeklappt wächst er zur Kapsel. */
  border-radius: 999px;
}
/* Nur die Kontur des Kreises, das i dunkel darin - das Zeichen wird dadurch
   deutlich leichter und drängt sich auf dem Foto nicht vor. */
.photo .info {
  flex: none; width: 1.05rem; height: 1.05rem; border-radius: 50%;
  border: 1.5px solid var(--credit-ink); background: none; cursor: pointer; padding: 0;
  /* Mittig, und zwar wirklich: Flex zentriert den Pfad, nicht eine Zeilenhöhe. */
  display: flex; align-items: center; justify-content: center;
}
.photo .info-glyph { width: .52rem; height: .52rem; fill: var(--credit-ink); display: block; }
/* Beim Zeigen füllt sich der Kreis - eine Rückmeldung, ohne die Ruhe zu opfern. */
.photo .info:hover { background: var(--credit-ink); }
.photo .info:hover .info-glyph { fill: var(--credit-grund); }
.photo .info:focus-visible { outline: 2px solid var(--credit-ink); outline-offset: 2px; }
.photo .credit {
  overflow: hidden; white-space: nowrap; max-width: 0; opacity: 0;
  /* **Die Zeilenhoehe bestimmt die Hoehe der Kapsel** - und die muss der Breite
     entsprechen, sonst ist der eingeklappte Grund kein Kreis, sondern ein
     abgerundetes Rechteck. Sie ist deshalb an die Groesse des Zeichens gebunden
     (1,05rem) und nicht frei gewaehlt: 20px Zeilenhoehe neben einem 16,8px
     hohen Zeichen ergaben 21,6 zu 24,8 - und genau so sah es aus. */
  font-size: .74rem; line-height: 1.05rem;
  transition: max-width .25s ease, opacity .2s ease, padding .25s ease;
}
/* Aufgeklappt bleibt er innerhalb des Bildes und bricht um, statt hinauszulaufen. */
.photo .credit-chip[data-open="true"] { max-width: calc(100% - 1.2rem); }
.photo .credit-chip[data-open="true"] .credit {
  max-width: 26rem; opacity: 1; padding: 0 .55rem 0 .4rem;
}
/* **„Stimmungsbild, nicht dieser Ort"** - der Zusatz an einem Bild mit
   `role: "mood"`. Er steht **hinter** dem Nachweis in derselben Zeile, mit dem
   Trennpunkt, den auch Urheber und Rechtegrundlage benutzt: Es ist dieselbe
   Auskunft, nur ihr letzter Teil. Ein eigener Absatz waere ein zweiter Satz in
   einer Kapsel, die eine Zeile hoch ist.

   **Ein Grad leiser** (`opacity`, nicht eine zweite Farbe): Der Nachweis ist
   die Pflicht, dies ist die Einordnung. Eine eigene Farbe waere im Dunkeln ein
   zweiter Wert, der geprueft werden muesste.

   Bis zum 09.09.2026 hatte diese Klasse keine Regel - es gab kein einziges
   Stimmungsbild im Bestand. Gefunden hat es `scripts/klassen.ts` beim ersten. */
.photo .credit .mood { opacity: .75; }
.photo .credit .mood::before { content: " · "; }
/* **Eine Zeile, kein Umbruch.** Ein Umbruch sieht im Ruhezustand gut aus und
   springt beim Aufklappen: Die Breite waechst von null, und bei null bricht der
   Text nach jedem Wort um - die Kapsel wird erst hoch und dann wieder flach.
   Deshalb bleibt es eine Zeile, und deshalb muss der Nachweis kurz sein (Name,
   Jahr, Lizenz nur wenn sie es fordert - siehe media.forLocation). Vollstaendig
   steht er ohnehin immer im Dokument, auch fuer ein Vorleseprogramm. */
.photo .credit a { color: var(--credit-ink); margin-left: .35rem; }
@media (prefers-reduced-motion: reduce) {
  .photo .credit { transition: none; }
}

/* Der Schwarzwald ist eckig.
   Keine abgerundeten Ecken, keine Pillen, keine Schatten als Zierde. Rundungen
   gibt es nur, wo die Form selbst rund ist: das i im Kreis, der Punkt im Pin.
   Diese Regel gilt fuer alles, was hier dazukommt. */

/* Die interaktive Wegkarte. Hoehe fest, damit die Seite beim Laden nicht
   springt - eine Karte, die sich ihre Hoehe erst vom Inhalt holt, schiebt beim
   Erscheinen alles darunter nach unten.

   Eckig, wie alles hier. MapLibre bringt eigene Rundungen an seinen Knoepfen
   mit; die werden hier zurueckgesetzt. */
/* **Eine Haarlinie ringsum** (18.09.2026) - `--line`, ein Pixel, und damit
   dieselbe Linie, mit der im Haus getrennt wird; im Dunkelmodus wird sie
   dunkel, ohne dass hier etwas dazukommt.

   **Das ist die Ausnahme von „eine Flaeche hat keinen Rahmen"**, und die
   Begruendung ist dieselbe wie bei der Kachel: Die Karte ist ein **Ding** und
   keine Flaeche der Oberflaeche. Ihr Inhalt kommt von woanders (Kacheln aus
   OpenStreetMap), er hat keine eigene Kante, und wo sie aufhoert, ist ohne
   Linie nicht zu sehen - am deutlichsten an einem hellen Ausschnitt, der ohne
   sie in die Seite ausfranst. Die Linie sagt: **bis hierher ist Karte.**

   `box-sizing: border-box` steht global, die Hoehe bleibt also, wie sie ist -
   es springt nichts nach. */
.tourmap {
  width: 100%; height: clamp(20rem, 52vh, 30rem);
  background: var(--shade);
  border: 1px solid var(--line);
  margin: .4rem 0 .6rem;
}

/**
 * **Solange die Karte laedt, steht das Wort darauf.**
 *
 * MapLibre holt seinen Arbeiter nach und liest danach das Kachelarchiv ueber
 * Bereichsabfragen; bis das Bild steht, vergehen auf einer kalten Verbindung
 * Sekunden. Ohne diesen Zustand ist die Flaeche weiss, die Bedienknoepfe sind
 * aber schon da - und das liest sich als Fehler und nicht als Wartezeit.
 *
 * `::after` und kein eigenes Element: Der Hinweis gehoert der Flaeche und
 * nicht dem Dokument - ein Vorleseprogramm bekommt den Zustand ueber
 * `aria-busy`, und ein Kind, das jemand einhaengt und wieder entfernt, ist ein
 * zweiter Ort fuer dieselbe Sache. Leise (`--soft`), weil es kein Ergebnis
 * ist, sondern ein Zwischenstand.
 */
/* Bezugspunkt fuer den Ladezustand **und** die Fehlerflaeche darunter. */
.tourmap { position: relative; }
.tourmap[data-laedt]::after {
  content: attr(data-laedt-wort);
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--soft); font-size: .95rem;
  pointer-events: none;
}
/* **Und wenn sie gar nicht kommt.**

   Der Ladezustand darueber ist ein `::after` und damit richtig - er sagt
   „gleich". Ein Fehler sagt „nicht" und braucht **einen Knopf**, also ein
   echtes Element: Wer umschaltet und einen grauen Kasten bekommt, weiss sonst
   nicht, ob er warten oder etwas tun soll. Mittig, leise, mit dem Knopf des
   Hauses - kein roter Kasten: Eine Karte, die beim zweiten Versuch da ist, ist
   keine Havarie. */
.karte-fehler {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .8rem; padding: 1.2rem; text-align: center;
}
.karte-fehler p { margin: 0; color: var(--soft); font-size: .95rem; }

.tourmap .maplibregl-ctrl,
.tourmap .maplibregl-ctrl button,
.tourmap .maplibregl-ctrl-group { border-radius: 0 !important; }
.tourmap .maplibregl-ctrl-attrib { font-size: .7rem; }
/* Die Naehekarte war flacher als die Wegkarte - **zu flach**: Die Klappe zu
   einer Nadel deckte sie fast zu, und dann sieht man die anderen Nadeln nicht
   mehr, die man eigentlich vergleichen wollte. Jetzt so hoch, dass eine Klappe
   in einer Ecke sitzt statt im Weg zu stehen. */
.tourmap-near { height: clamp(20rem, 52vh, 30rem); margin-bottom: 1rem; }
.tourmap .maplibregl-ctrl-attrib a { color: var(--ink); }

/* Fragen und Antworten als Aufklapper.
   Die Frage steht fett, das Zeichen rechts, darunter eine Linie - und die
   Antwort klappt darunter auf. Eingeklappt ist der Text trotzdem im Dokument;
   `<details>` versteckt ihn nur, es entfernt ihn nicht. Das ist der Grund fuer
   dieses Element und nicht fuer eine eigene Bauweise: Der Fragenteil ist der
   Grund, warum diese Seiten existieren. */
/**
 * **Der redaktionelle Teil unter den Treffern.**
 *
 * Abstand nach oben, damit er sich von der Liste loest - er ist ein zweiter
 * Teil der Seite und kein Nachsatz zur letzten Kachel. Die Lesespalte ist
 * dieselbe wie ueberall (`--text`): Zeilen, die man ohne Kopfdrehung liest,
 * sind im ganzen Guide gleich lang.
 */
/* Mittig wie alles, was Text ist - dieselbe Achse wie der lange Text einer
   Eintragsseite. Der Text darin bleibt linksbuendig: zentrierte Absaetze liest
   man schlechter, weil jede Zeile woanders anfaengt. */
.editorial { margin: 3.2rem auto 0; max-width: var(--text); }
.editorial > h2 { margin-top: 2rem; }
.editorial > h2:first-child { margin-top: 0; }
.editorial-text p { margin: 0 0 1rem; font-size: 1.02rem; line-height: 1.65; }
.editorial-text p:last-child { margin-bottom: 0; }
/* **Die Abschnitte im Seitentext** (07.09.2026, `item.js richtext`). Ein Text
   mit eigener Gliederung bringt `h2` und `h3` mit; die Ueberschrift "Ueber
   <Thema>" faellt dann weg, also fangen sie **hier** die Aufgabe auf, den
   Abstand vor einem Abschnitt zu setzen. Mehr Luft oben als unten - eine
   Ueberschrift gehoert zu dem, was unter ihr steht, und die 2 rem sind
   dieselben wie an `.editorial > h2`. */
.editorial-text h2 { margin: 2.4rem 0 .7rem; }
.editorial-text h3 { margin: 1.8rem 0 .5rem; }
.editorial-text > :first-child { margin-top: 0; }
/* Ein Verweis im Fliesstext bleibt einer: unterstrichen, in Textfarbe - die
   Regel dafuer steht bei den Textlinks und braucht hier keine zweite. */
/**
 * **Der Textlink: schwarz, unterstrichen, Pfeil dahinter.**
 *
 * Ein Verweis im Fliesstext soll aussehen wie ein Verweis - unterstrichen, in
 * der Textfarbe, nicht in einer Sonderfarbe. Der Pfeil dahinter ist derselbe
 * wie in der Navigation (`icon("arrow")`): dort sagt er "hier geht es weiter",
 * und dieselbe Aussage soll dasselbe Zeichen haben.
 *
 * Als **Maske** und nicht als eingebettetes SVG, damit die Klasse allein
 * genuegt: `<a class="textlink">` und fertig, ohne dass ein Skript ein Zeichen
 * einsetzen muss. Der Pfad steht damit ein zweites Mal im Stilblatt - derselbe
 * Handel wie beim X im Suchfeld, aus demselben Grund: CSS kann kein Skript
 * aufrufen.
 *
 * Der Pfeil rueckt beim Zeigen ein Stueck nach rechts. Zwei Pixel, keine
 * Animation um ihrer selbst willen: Er zeigt, dass der Verweis lebt, und die
 * Bewegung geht in die Richtung, in die er fuehrt.
 */
.textlink {
  color: var(--strong); text-decoration: underline;
  text-underline-offset: .18em;
  display: inline-flex; align-items: center; gap: .3rem;
}
.textlink::after {
  content: ""; width: .95em; height: .95em; flex: none;
  background: currentColor;
  -webkit-mask: var(--icon-arrow) center / contain no-repeat;
  mask: var(--icon-arrow) center / contain no-repeat;
  transition: transform .18s ease;
}
.textlink:hover::after, .textlink:focus-visible::after { transform: translateX(2px); }
@media (prefers-reduced-motion: reduce) {
  .textlink::after { transition: none; }
}

/* ---------------------------------------------------------------------------
   **JEDE FRAGE IN IHRER EIGENEN BOX**  (10.09.2026)
   ---------------------------------------------------------------------------

   Vorher war die Liste eine Folge von Trennlinien: eine Zeile, ein Strich
   darunter. Das las sich als **eine** lange Liste, in der man die Grenze
   zwischen Antwort und naechster Frage suchen muss - besonders, wenn zwei
   offen sind. Ein Kasten je Frage macht jede zu einer Sache.

   **Die Kante sagt den Zustand:** grau (`--line`, derselbe Ton wie die
   Trennlinie vorher), und aufgeklappt **schwarz** (`--strong`). Kein zweiter
   Grund, keine zweite Schrift - nur die Linie, die schon da war, wird zum
   Rahmen und beim Oeffnen kraeftiger. Das ist dieselbe Grammatik wie ueberall
   im Haus: Der Zustand steckt in der Flaeche oder der Kante, nicht in einer
   Farbe daneben.

   **Vier Pixel Radius** - eine der dokumentierten Ausnahmen von
   `border-radius: 0`, und ausdruecklich **dieselbe** wie am Hilfezeichen und
   an der Infobox: Wenn die Marke schon eine Ausnahme bekommt, dann eine, und
   nicht drei verschiedene.

   `overflow: hidden` haelt die Antwort in der Rundung; ohne das schiebt sich
   ein langer Absatz an der Ecke ueber die Kante. */
.qa {
  border: 1px solid var(--line);
  border-radius: 4px;
  margin: 0 0 .6rem;
  padding: 0 1rem;
  overflow: hidden;
  transition: border-color .12s ease-in-out;
}
.qa[open] { border-color: var(--strong); }
@media (prefers-reduced-motion: reduce) {
  .qa { transition: none; }
}
.qa summary {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
  padding: .9rem 0; cursor: pointer;
  font-weight: 700; font-size: 1.02rem; line-height: 1.35;
  list-style: none;
}
/* Das eigene Zeichen der Browser muss weg - Safari braucht dafuer eine eigene
   Zeile. */
.qa summary::-webkit-details-marker { display: none; }
.qa summary::marker { content: ""; }
/* Plus und Minus, zwei Striche aus dem Stylesheet. Ein Bild waere eine Datei
   fuer zwei Striche - und ein Zeichen aus einem Satz eine Nennungspflicht. */
.qa summary::after {
  content: ""; flex: none; position: relative;
  width: .85rem; height: .85rem; margin-top: .25rem;
  background:
    linear-gradient(var(--strong), var(--strong)) center/100% 1.5px no-repeat,
    linear-gradient(var(--strong), var(--strong)) center/1.5px 100% no-repeat;
}
.qa[open] summary::after {
  background: linear-gradient(var(--strong), var(--strong)) center/100% 1.5px no-repeat;
}
.qa summary:hover, .qa summary:focus-visible { color: var(--accent); }
.qa summary:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* Der Abstand nach unten steht im Kasten (`padding` am offenen Kasten), nicht
   am Absatz - sonst haette die Antwort zweimal Luft und die Box saehe unten
   leer aus. **Und der letzte Absatz traegt nichts:** Bereiche wie
   `.about-block` oder `.item-text` nullen ihr `p:last-child`; haenge der
   Abstand am Absatz, klebte die Antwort dort an der Linie. Mit `details.qa`
   ist die Regel staerker als jede dieser Bereichsregeln.

   **Keine eigene Breite:** Die Antwort ist so breit wie ihr Kasten. Der steht
   ohnehin schon in der Lesespalte (`--text` an seinem Behaelter), und eine
   zweite Grenze am Absatz waere eine zweite Antwort auf dieselbe Frage - im
   Bild eine Kante, die auf halber Strecke im Kasten endet. */
.qa > p { margin: 0 0 1rem; }
.qa[open] { padding-bottom: 1.5rem; }
details.qa > :last-child { margin-bottom: 0; }

/* Die Handlungszeile: hinfahren, mitnehmen. Zwei Knoepfe, gleich gebaut - einer
   ist ein Link nach draussen, einer laedt eine Datei, und das sieht man am
   Zusatz darunter statt an der Form. Eckig, schwarzer Rahmen, kein Schatten. */
/* **Linksbuendig, an derselben Kante wie der Text.**
   Zentriert stand die Zeile zwar auf der Achse von Name und Ort - aber zwei
   Knoepfe nebeneinander bilden dabei eine Gruppe, deren linker Rand sich mit
   jedem dazukommenden Knopf verschiebt. An der Textkante beginnt der erste
   Knopf immer an derselben Stelle, egal ob einer, zwei oder drei dastehen. */
.actions {
  display: flex; flex-wrap: wrap; justify-content: flex-start; gap: .6rem;
  margin: 1rem 0 2.2rem;
}
/* **Der Maps-Knopf steht jetzt im Wert der Adresszeile** (03.09.2026), nicht
   mehr in einer eigenen Zeile unter der Tabelle. Vorher zog ein negativer
   Randabstand die Knopfzeile optisch an die Adresse heran - gegen die
   Struktur, denn dazwischen lagen Telefon, Website und Oeffnungszeiten.
   Deshalb hier nur ein knapper Abstand nach oben und keiner nach unten: Der
   Knopf sitzt in der Zelle, und die Zelle hat ihr eigenes Polster. */
.actions-inline { margin: .7rem 0 0; }
/* Und die Falle dabei: `.pairs dd a` faerbt **jeden** Link in der Tabelle auf
   die Textfarbe und ist spezifischer als `.action-primary`. Ohne diese zwei
   Zeilen stuende die Schrift des Knopfes in Tintenschwarz auf schwarzem Grund
   - lesbar erst beim Darueberfahren. */
.pairs dd a.action-primary { color: var(--paper); }
.pairs dd a.action-primary:hover,
.pairs dd a.action-primary:focus-visible { color: var(--strong); }
.action {
  display: inline-flex; align-items: center; justify-content: center; gap: .45rem;
  flex-wrap: wrap; min-height: var(--feld-hoehe);
  border: 1px solid var(--strong); background: var(--paper); color: var(--strong);
  border-radius: var(--feld-radius);
  padding: .55rem .8rem; font: inherit; font-size: .92rem; text-decoration: none;
  cursor: pointer;
}
.action:hover, .action:focus-visible { background: var(--strong); color: var(--paper); }
.action:hover .glyph, .action:focus-visible .glyph { color: var(--paper); }
.action:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
.action[disabled] { opacity: .5; cursor: default; }

/* **Der schwarze Knopf: das ist die Handlung.**
   Auf einer Wegseite tragen ihn beide - „Führe mich dort hin" und „GPX laden".
   Vorher blieb der GPX-Knopf umrandet, damit nur eine Hauptsache dasteht; er
   sah damit aber wie ein Nebenausgang aus, und beide sind dasselbe: der Weg
   hinaus aus der Seite und hinein in den Tag. Entschieden am 03.09.2026. */
.action-primary { background: var(--strong); color: var(--paper); border-color: var(--strong); }
.action-primary .glyph { color: var(--paper); }
.action-primary:hover, .action-primary:focus-visible {
  background: var(--paper); color: var(--strong);
}
.action-primary:hover .glyph, .action-primary:focus-visible .glyph { color: var(--strong); }

/* Auf dem Telefon nehmen die Knoepfe die ganze Breite: Nebeneinander bleiben
   von 320 Pixeln je 140 - dort steht keine Beschriftung mehr, und der Zusatz
   darunter bricht um. */
@media (max-width: 34rem) {
  .actions { flex-direction: column; }
  .action { width: 100%; justify-content: center; text-align: center; }
}
/**
 * **The error page stands on one axis** (`site/pages/404.astro`): clock,
 * heading, two sentences, two buttons. It is a short block with nothing beside
 * it, so the buttons follow the axis too - the left-edge rule above is for
 * buttons under a text column, and here there is no column.
 *
 * The clock is a silhouette in `currentColor`, its inner drawing cut out by a
 * mask (`scripts/kuckucksuhr.py`) - so it takes `--strong`, turns with the
 * theme and needs no second version. Its cuts are 3 units wide: at 180 px
 * that is 2.25 px, at 168 px on a phone 2.1 px, and nothing closes up.
 * The sentence under the heading is body text, not a `.lead`: on this page
 * the clock and the heading carry the weight.
 */
.fehlerseite {
  max-width: var(--text); margin: 0 auto; padding: 1.5rem 0 1rem;
  text-align: center;
}
.fehlerseite-bild { margin: 0 auto 1.5rem; width: 11.25rem; color: var(--strong); }
.fehlerseite-bild svg { display: block; width: 100%; height: auto; }
.fehlerseite h1 { margin: 0 0 .8rem; }
.fehlerseite-nowrap { white-space: nowrap; }
.fehlerseite-text { margin: 0 auto; }
.fehlerseite .actions { justify-content: center; margin: 1.8rem 0 0; }
@media (max-width: 34rem) {
  .fehlerseite-bild { width: 10.5rem; }
}
/* Der Zusatz sagt, was passiert: "oeffnet Google Maps" steht **vor** dem Klick
   da, nicht danach. */

/* ---------------------------------------------------------------------------
   Einstiegsseite eines Ortes. Kopfbild, Ueberschrift, Einleitung - darunter,
   was es wirklich gibt. Vorbild tirol.at.
   --------------------------------------------------------------------------- */

/* Das Kopfbild steht ueber die ganze Inhaltsbreite und ist flacher als eine
   Kachel: Ein Kopf ist ein Streifen, kein Bild zum Ansehen. 21 zu 9 auf dem
   Desktop, 3 zu 2 auf dem Telefon - dort waere ein Streifen eine Leiste. */
.hero { position: relative; margin: 0 0 1.2rem; }
.hero .photo { margin: 0; }
.hero .photo img { aspect-ratio: 3 / 2; }
@media (min-width: 46rem) {
  .hero .photo img { aspect-ratio: 21 / 9; }
}
/* Der kleine Verweis unten rechts: **welcher Eintrag** darauf zu sehen ist.
   Auf eigenem weissen Grund, damit er auf jedem Foto lesbar bleibt - und
   bewusst klein: Er ordnet ein, er wirbt nicht. */
.hero-from {
  position: absolute; right: 0; bottom: 0;
  background: var(--paper); color: var(--strong); text-decoration: none;
  font-size: .78rem; padding: .35rem .6rem;
}
.hero-from:hover, .hero-from:focus-visible { color: var(--accent); text-decoration: underline; }

.ort-intro { max-width: 42rem; }

/* ---------------------------------------------------------------------------
   Ueber mich: die einzige Seite, auf der ein Mensch spricht.
   ---------------------------------------------------------------------------

   Eine Lesespalte, sonst nichts. Keine Kacheln, keine Karte, kein Filter - was
   hier steht, liest man von oben nach unten. Die Breite ist dieselbe wie beim
   langen Text einer Eintragsseite (`--text`): Zeilen, die man ohne Kopfdrehung
   liest, sind ueberall gleich lang. */
.about { max-width: var(--text); margin: 0 auto; }
.about > h1 { margin-bottom: .6rem; }
/* Groesse und Farbe stehen bei `.lead` selbst - hier nur der Abstand zum
   ersten Abschnitt. Auf diesen Seiten folgt eine Ueberschrift, und die braucht
   mehr Luft als eine Zaehlzeile oder eine Suchzeile. */
.about > .lead { margin: 0 0 2.4rem; }
.about-block { margin: 0 0 2.2rem; }
/**
 * **Unter dem Vorspann bringt die erste Ueberschrift keinen zweiten Abstand
 * mit** (05.09.2026).
 *
 * `.about > .lead` gibt 2.4 rem nach unten, ein `h2` nimmt sich 2.6 rem nach
 * oben - und weil die Bloecke in einem eigenen Kasten liegen, fallen die
 * beiden Abstaende **nicht** zusammen, sondern kommen aufeinander: 5 rem
 * Loch zwischen dem Satz, der die Seite ansagt, und ihrem ersten Abschnitt.
 * Zwischen zwei Abschnitten sind es 2.6 rem; genau dort liegt der Vorspann
 * jetzt auch.
 *
 * **Nur mit Vorspann** (`:has`): Ohne ihn steht die Ueberschrift direkt unter
 * dem Titel der Seite (`.about > h1`, 0.6 rem) - und 0.6 rem unter einer h1
 * ist keine Gliederung mehr, sondern eine zweite Zeile desselben Titels. Die
 * Datenschutzseite hat keinen Vorspann und ist genau dieser Fall.
 */
.about:has(> .lead) .about-block:first-child > h2:first-child { margin-top: 0; }
.about-block p { margin: 0 0 1rem; font-size: 1.02rem; line-height: 1.65; }
.about-block p:last-child { margin-bottom: 0; }
/* Die Aufzaehlung mit Abstand statt mit Punkten: Jeder Eintrag ist ein eigener
   Weg, kein Stichwort in einer Reihe. Der senkrechte Strich links bindet sie
   zusammen, ohne sie zu numerieren - es gibt keine Reihenfolge darin. */
/**
 * **Unter der Liste derselbe Abstand wie unter einem Absatz** (04.09.2026).
 *
 * Vorher hatte sie nur oben einen: `1rem 0 0`. Solange eine Liste einen
 * Abschnitt beendete, fiel das nicht auf - in den Teilnahmebedingungen folgt
 * jetzt aber Text auf die Liste („Alles, was darüber hinausgeht ..."), und der
 * klebte an der letzten Zeile. Ein Absatz gibt 1rem nach unten, also gibt die
 * Liste dasselbe: Sie ist im Fließtext ein Absatz und keine Sonderform.
 *
 * Als letztes Kind wieder nichts - sonst zählt der Abstand des Abschnitts
 * doppelt, dieselbe Regel wie bei `p:last-child`.
 */
.about-list { list-style: none; margin: 1rem 0; padding: 0; }
.about-list:last-child { margin-bottom: 0; }
.about-list li {
  margin: 0 0 .9rem; padding: 0 0 0 1rem;
  border-left: 2px solid var(--line);
  font-size: 1.02rem; line-height: 1.6;
}
.about-list li:last-child { margin-bottom: 0; }

/**
 * **Das Zitat im Fließtext** (05.09.2026) - „Ich bin ein Macher. Machst du mit?"
 *
 * Dieselbe Sprache wie in der Einladungsmail (`convex/mailTemplates.ts
 * zitat`): ein Strich links, kein Kasten und keine Anführungszeichen im Text.
 * Ein Rahmen um einen Satz ist eine Auszeichnung, ein Rand ist eine Stimme -
 * und wer die Mail bekommen hat, erkennt den Satz auf der Seite wieder.
 *
 * Der Strich ist **so dick wie der einer Listenzeile** und nur schwarz statt
 * grau: Es gibt eine Strichstärke, Gewicht macht hier die Farbe. Und die
 * Schrift ist größer als ein Absatz, weil der Satz keine Aussage ist, sondern
 * eine Frage an den, der ihn liest.
 */
.about-zitat {
  margin: 1.6rem 0; padding: .1rem 0 .1rem 1rem;
  border-left: 2px solid var(--strong);
  font-size: 1.25rem; line-height: 1.35; font-weight: 700; color: var(--strong);
}
.about-zitat:last-child { margin-bottom: 0; }

/* **The polaroid beside "who I am"** - on the screen 24 rem wide, floating
   right of the text; on the phone across the whole width above it. It is a picture of a thing you hold,
   so it may lie at an angle (the tilt is in the photo itself); the cut-out
   background makes it lie on the paper of the page. */
.about-portrait { display: block; width: 100%; height: auto; margin: 0 0 1.4rem; }
@media (min-width: 40rem) {
  .about-portrait { float: right; width: 24rem; margin: -.4rem -1rem 1rem 1.6rem; }
  .about-block:has(> .about-portrait) { display: flow-root; }
}

/**
 * **Die drei Skizzen in den Teilnahmebedingungen** (08.09.2026).
 *
 * Zwei Etagen je Skizze: oben der Grundriss (wo du stehst), unten der
 * Bildausschnitt (was dabei herauskommt). Gezeichnet wird in
 * `scripts/skizzen-haus.py`, die Bilder liegen unter `/media/skizzen/`.
 *
 * **Es ist ein Bild und trotzdem kein `img`.** Ein PNG hat feste Farben, und
 * die Hausregel "hell und dunkel, immer" gilt weiter - mit drei Zustaenden:
 * die Voreinstellung des Geraets, die ausdrueckliche Wahl "hell" und die
 * ausdrueckliche Wahl "dunkel". Also liegt hier nicht das Bild selbst, sondern
 * seine **Deckung**: Die PNG-Datei traegt im Alphakanal, wie dicht die Tusche
 * an dieser Stelle ist, und `mask-image` stanzt damit eine Flaeche in
 * `var(--strong)` aus. Hell heisst schwarze Tusche auf weissem Grund, dunkel
 * weisse auf dunklem - und jeder Zwischenton geht mit, ohne dass irgendwo eine
 * zweite Datei gepflegt werden muesste.
 *
 * **Der Preis, offen genannt:** Ohne `img` gibt es kein `loading="lazy"` - die
 * drei Bilder (zusammen rund 150 kB) kommen mit der Seite. Dafuer gibt es sie
 * nur einmal statt zweimal, und sie folgen dem Token auch dann noch, wenn
 * jemand die Palette aendert. Der Alternativtext steht am Element
 * (`role="img"` plus `aria-label`), das Seitenverhaeltnis haelt `aspect-ratio`
 * - damit springt beim Laden nichts.
 *
 * **Kann ein Browser keine Maske, bleibt die Unterschrift stehen.** Sie traegt
 * die Regel in Worten; ein leeres schwarzes Rechteck waere schlimmer als kein
 * Bild.
 */
.about-skizze { margin: 1.6rem 0; }
.about-skizze:last-child { margin-bottom: 0; }
.skizze {
  display: block; width: 100%; aspect-ratio: 600 / 292;
  background-color: var(--strong);
  -webkit-mask-image: var(--skizze); mask-image: var(--skizze);
  -webkit-mask-size: 100% 100%;      mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;    mask-repeat: no-repeat;
}
@supports not ((-webkit-mask-image: url("")) or (mask-image: url(""))) {
  .skizze, .skizze-worte { display: none; }
}
/**
 * **Die Wortzeile steht in der Seite und nicht im Bild.**
 *
 * Im SVG war sie 13 Zeichenmass gross, also bei halber Breite sechs Pixel -
 * es brauchte eine zweite Groesse per Medienabfrage, damit sie ueberhaupt
 * lesbar blieb. Als Text ist sie in jeder Breite gleich gross und gleich
 * scharf, sie laesst sich ohne den Renderer aendern, und wenn diese Seite
 * jemals uebersetzt wird, muss dafuer kein Bild neu gerechnet werden.
 *
 * Das Raster ist das Blattmass: 15 Rand, 260 Ausschnitt, 50 Luft, 260
 * Ausschnitt, 15 Rand. So steht jedes Wort unter seinem eigenen Ausschnitt,
 * in jeder Breite.
 */
.skizze-worte {
  display: grid; grid-template-columns: 15fr 260fr 50fr 260fr 15fr;
  margin: .45rem 0 0; font-size: .82rem; line-height: 1.3; color: var(--soft);
}
.skizze-worte span:first-child { grid-column: 2; }
.skizze-worte span:last-child  { grid-column: 4; }
.about-skizze figcaption {
  margin: .6rem 0 0; font-size: .92rem; line-height: 1.5; color: var(--soft);
}
.about-skizze figcaption strong { color: var(--ink); }

/* ---------------------------------------------------------------------------
   Das Abschnittsverzeichnis der Rechtsseiten
   ---------------------------------------------------------------------------

   Die Teilnahmebedingungen haben fünfzehn Abschnitte, und fast niemand liest
   sie von oben nach unten: Man kommt mit einer Frage („darf mein Bild
   weiterverkauft werden?") und sucht die eine Stelle. Ein Verzeichnis daneben
   ist die Antwort darauf - und weil es aus den Abschnitten selbst entsteht
   (`recht.js`), kann es nicht veralten.

   **Links und nicht oben**, damit es beim Lesen stehen bleibt: Wer im letzten
   Drittel merkt, dass er im falschen Abschnitt ist, soll nicht erst nach oben
   zurück müssen. Klebend also - und nur dort, wo es eine zweite Spalte
   überhaupt gibt. */
/**
 * **Ab wann es die zweite Spalte gibt - eine Zahl, zwei Leser.**
 *
 * Die Breite entscheidet zweierlei: ob das Raster zwei Spalten hat (hier) und
 * ob das Verzeichnis aufgeklappt gezeichnet wird (`recht.js`). Getippt stünde
 * dieselbe Zahl an zwei Stellen, und die zweite wäre die, die beim nächsten
 * Verschieben vergessen wird. Deshalb ein Schalter: Das Stylesheet setzt ihn,
 * das Skript liest ihn ab.
 */
:root { --toc-offen: 0; }
/**
 * **Ein hellgrauer Rahmen um das Verzeichnis - nur auf dem Telefon.**
 *
 * Ohne Rahmen war dort nicht zu sehen, wie weit das Verzeichnis reicht: Ein
 * Wort „Abschnitte", darunter fünfzehn Zeilen, und beides schwebte im
 * Fließtext. Der Rahmen sagt, wo es anfängt und wo es aufhört.
 *
 * **Er bleibt hellgrau, in jedem Zustand.** Der Rahmen ist die Umgrenzung einer
 * Fläche und keine Auskunft - was gerade gilt, sagen der Pfeil (auf oder zu)
 * und der Strich an der gelesenen Zeile. Ein Rahmen, der die Farbe wechselt,
 * wäre ein dritter Sprecher für dieselbe Sache.
 *
 * In der linken Spalte ab 68rem steht er nicht - dort grenzt schon die Spalte
 * selbst ab, siehe unten.
 */
.toc {
  margin: 0 0 2.2rem;
  border: var(--toc-strich) solid var(--line);

  /**
   * **Drei Masse, aus denen alles andere folgt.**
   *
   * `--toc-strich` ist **eine** Strichstaerke fuer das ganze Bauteil: der
   * Rahmen, die Linien an den Zeilen **und der Strich des Pfeils**. Der Pfeil
   * kommt aus einer Maske, seine Staerke laesst sich dort nicht setzen - sie
   * folgt der Groesse: Das Zeichen steht im 24er Raster und ist mit Staerke 2
   * gezeichnet, ein Zwoelftel seiner Kantenlaenge. Also ist die Kantenlaenge
   * `12 x Strich`, und der gezeichnete Strich trifft die Linie darunter auf den
   * Punkt - bei jeder Schriftgroesse, weil die Rechnung und nicht die Zahl
   * dasteht.
   *
   * `--toc-rand` ist der Innenabstand. Er steht hier, weil der Einzug der
   * Liste aus ihm **abgeleitet** wird: Die Linien sollen die Achse des Pfeils
   * fortsetzen, und die liegt eine halbe Pfeilbreite weiter rechts.
   */
  --toc-strich: 1px;
  --toc-pfeil: calc(var(--toc-strich) * 12);
  --toc-rand: 1rem;
}
/* Der Aufklapper ist die Form für das Telefon: Fünfzehn Zeilen Verzeichnis vor
   dem ersten Satz wären dort eine Hürde. Die Innenabstände sitzen an Griff und
   Verzeichnis, nicht am Rahmen: So reicht die Schaltfläche von Kante zu Kante
   und nicht nur bis unter das Wort. */
.toc > summary {
  display: flex; align-items: center; gap: .55rem;
  cursor: pointer; padding: .75rem var(--toc-rand);
  font-size: .95rem; font-weight: 700; color: var(--strong);
  list-style: none;
}
/* Das eigene Zeichen der Browser muss weg - Safari braucht dafür eine eigene
   Zeile. Genau wie bei `.qa`. */
.toc > summary::-webkit-details-marker { display: none; }
.toc > summary::marker { content: ""; }
/**
 * **Der Pfeil der Galerie, gedreht** - nicht das Dreieck des Browsers.
 *
 * Vorher stand hier das Systemdreieck mit der Begründung, ein eigenes Zeichen
 * kenne niemand. Das gilt nicht mehr: Der gerade Pfeil mit Strich und Spitze
 * blättert in der Galerie weiter, steht am Textverweis und im Aufklapper der
 * Navigation - er ist im Guide **das** Zeichen für „einen Schritt weiter". Das
 * Dreieck war das einzige Zeichen der Oberfläche, das von woanders kam.
 *
 * Zu heißt nach unten, offen heißt nach oben: die Richtung, in die die Fläche
 * geht. Gedreht wird eine Form, gezeichnet wird keine zweite.
 *
 * **Vor dem Wort und nicht am rechten Rand**, weil er zu „Abschnitte" gehört
 * und nicht zum Kasten: Zeichen und Wort sagen dasselbe, also stehen sie
 * beieinander. Am anderen Ende der Zeile wäre er ein zweiter Anfang.
 */
.toc > summary::before {
  content: ""; flex: none;
  width: var(--toc-pfeil); height: var(--toc-pfeil);
  background: currentColor;
  -webkit-mask: var(--icon-arrow) center / contain no-repeat;
  mask: var(--icon-arrow) center / contain no-repeat;
  transform: rotate(90deg);
  transition: transform .18s ease;
}
.toc[open] > summary::before { transform: rotate(-90deg); }
.toc > summary:hover { color: var(--accent); }
.toc > summary:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .toc > summary::before { transition: none; }
}
/**
 * **Die Linien stehen auf der Achse des Pfeils - nicht daneben.**
 *
 * Der Pfeil zeigt zugeklappt nach unten; sein Schaft ist dann eine senkrechte
 * Linie durch die Mitte seines Kastens. Genau dort setzen die Linien der Zeilen
 * an: Sie sind die Fortsetzung dieses Schafts nach unten, in derselben Staerke.
 * Am linken Rand des Pfeilkastens standen sie vorher eine halbe Pfeilbreite
 * daneben - nah genug, um wie ein Versehen auszusehen.
 *
 * Die Rechnung: Rand + halber Pfeil, minus den halben Strich, weil die Linie
 * von ihrer linken Kante aus waechst und nicht von ihrer Mitte.
 */
.toc nav ul {
  list-style: none; margin: 0;
  padding: 0 var(--toc-rand) .9rem
           calc(var(--toc-rand) + (var(--toc-pfeil) - var(--toc-strich)) / 2);
}
.toc nav li { margin: 0; }
/* Dieselbe Sprache wie `.about-list`: der senkrechte Strich links, der die
   Zeilen zusammenbindet, ohne sie zu numerieren. Die Abschnitte haben keine
   Nummern, also hat das Verzeichnis auch keine. */
.toc nav a {
  display: block; padding: .32rem 0 .32rem .9rem;
  border-left: var(--toc-strich) solid var(--line);
  color: var(--ink); text-decoration: none;
  font-size: .85rem; line-height: 1.5;
}
.toc nav a:hover, .toc nav a:focus-visible { color: var(--strong); border-left-color: var(--soft); }
/* Der Abschnitt, in dem gerade gelesen wird - `recht.js` misst ihn mit. Er
   trägt Farbe **und** Gewicht **und** eine schwarze Linie: Ein
   Graustufenunterschied allein wäre auf einem schlechten Bildschirm keine
   Auskunft. Die Linie wird nicht dicker, seit es **eine** Strichstärke gibt -
   sie wechselt nur die Farbe, wie der Rahmen es gerade nicht tut. */
.toc nav a[aria-current="true"] {
  color: var(--strong); font-weight: 700; border-left-color: var(--strong);
}

/* Der Sprung soll unter dem klebenden Block landen und nicht darunter
   verschwinden. Die Zahl steht hier und nur hier - `scrollIntoView()` in
   `recht.js` beachtet sie von selbst. */
.about-block[id] { scroll-margin-top: calc(var(--navheight, 3.7rem) + 1.2rem); }
/* ---------------------------------------------------------------------------
   DIE WALDPOST - Feld und Knopf sind ein Stück
   ---------------------------------------------------------------------------

   **Eine Zeile, kein Kasten.** Das Formular steht auf der Newsletterseite
   zwischen Vorspann und Text und soll später auch unter einem Eintrag stehen -
   ein umrandeter Kasten würde dort mit der Karte und den Angaben um
   Aufmerksamkeit streiten. Feld und Knopf reichen: Was es ist, sagt die
   Überschrift darüber.

   **Und sie stehen aneinander, nicht nebeneinander.** Ein Abstand dazwischen
   macht aus einer Handlung zwei Dinge - eine Zeile zum Ausfüllen und irgendwo
   daneben ein Knopf. Angesetzt sind es ein Feld mit einem Ende: Was man tippt,
   geht dort hinein, wo man drückt. Die zwei Rahmen werden dabei zu **einer**
   Kante (`margin: -1px` am Knopf), sonst stünde zwischen beiden ein Strich von
   zwei Pixeln, und der wäre die dickste Linie des Formulars.

   Auf dem Telefon fällt der Knopf unter das Feld und wird so breit wie die
   Spalte - ein halb so breiter Knopf neben einem halb so breiten Feld ist auf
   360 px zwei zu kleine Ziele. Das Stück bleibt eines: derselbe Kniff
   senkrecht, der Knopf sitzt auf der Unterkante des Feldes.

   **Die Schwelle dafür ist 34 rem, weil das Haus sie dort setzt** - unter
   dieser Breite bekommt jeder `.action` die volle Breite (die Regel bei den
   Knöpfen), und damit bricht die Zeile um, ob dieses Bauteil es will oder
   nicht. Eine eigene Zahl daneben wäre ein Band, in dem der Knopf schon unten
   steht und noch seitlich angesetzt ist. */
.waldpost-block { margin: 0 0 2.4rem; }
.waldpost { display: flex; flex-wrap: wrap; gap: 0; margin: 0; }
.waldpost-feld { flex: 1 1 16rem; }
/* **Field and button are one piece** - rounded on the outside, square at the
   seam, wherever the form stands (the page, a post, the invitation layer). A
   rounded corner at the seam made two parts of it, with a notch between them.
   On the phone the button stands below the field, so the seam is horizontal. */
.waldpost .waldpost-feld { border-radius: 4px 0 0 4px; }
.waldpost .action { border-radius: 0 4px 4px 0; }
@media (max-width: 34rem) {
  .waldpost .waldpost-feld { border-radius: 4px 4px 0 0; }
  .waldpost .action { border-radius: 0 0 4px 4px; }
}
/* Der Knopf so hoch wie das Feld - sonst sitzt er 2 px höher und die Zeile
   franst aus (derselbe Grund wie bei `min-height` an den Feldern oben). */
.waldpost .action {
  flex: 0 0 auto; min-height: 2.8rem; justify-content: center;
  margin-left: -1px;
}
/* **Der Fokusring liegt innen.** Draußen (`2px`, wie an jedem Knopf des
   Hauses) läuft er über die Kante ins Feld hinein, reißt dort den Rahmen auf
   und hebt den Knopf sichtbar aus der Leiste heraus - derselbe Grund, aus dem
   ihn der Zurückknopf, die Navigationszeile und das Suchfeld nach innen
   legen: Was bündig an etwas anderem sitzt, hat draußen keinen Platz. */
.waldpost .action:focus-visible { outline-offset: -3px; }
@media (max-width: 34rem) {
  .waldpost .action { flex: 1 1 100%; margin-left: 0; margin-top: -1px; }
}
/* **In der Kontrastdarstellung steht der Abstand wieder da.** Dort setzt das
   System die Flächen, und die Füllung des Knopfes ist das Einzige, was ihn vom
   Feld unterscheidet - ohne sie wären zwei angesetzte Rechtecke mit derselben
   Kante ein Feld mit einem Wort darin. */
@media (forced-colors: active) {
  .waldpost { gap: .6rem; }
  .waldpost .action { margin: 0; }
}
/* Der Wortlaut der Einwilligung. Klein, aber nicht versteckt: Er steht direkt
   unter dem Knopf, den er meint - nicht in einer Fußzeile drei Bildschirme
   tiefer. */
.waldpost-recht {
  margin: .7rem 0 0; font-size: .86rem; line-height: 1.5; color: var(--soft);
  max-width: 34rem;
}
.waldpost-fertig:not([hidden]) { margin: 0; }

/* ---------------------------------------------------------------------------
   **DAS ANMELDEFELD IM TEXT: BLAU MIT HOEHENLINIEN**
   ---------------------------------------------------------------------------

   Im Fliesstext eines Beitrags ist `[[newsletter]]` eine **Unterbrechung** -
   ein Formular zwischen zwei Absaetzen, das nichts mit dem Satz davor zu tun
   hat. Der Kasten sagt das, bevor man liest: eigene Flaeche, eigene Farbe. Auf
   der Seite `/newsletter/` bleibt das Formular dagegen nackt - dort ist es der
   Inhalt der Seite und braucht keine Kante um sich selbst.

   **Blau und Hoehenlinien sind eine Flaeche der Marke** - dieselbe Kombination
   wie `bg-hoehenlinien-blue` im Magazin. Die Linien im SVG sind weiss mit
   15 Prozent Deckung; sie werden nur auf dunklem Grund sichtbar, deshalb steht
   die Farbe zuerst und das Bild darueber - wie im Fuss und in der Kachel ohne
   Bild. `cover` und `center`, damit das Muster eine Flaeche bleibt und nicht
   kachelt.

   **Umgestellt wird ueber die Token, nicht ueber sechs Ausnahmen.** Innerhalb
   des Kastens ist Papier das Blau und Schwarz das Weiss - damit dreht sich
   alles darin von selbst mit: der Knopf (weiss auf Blau, beim Zeigen
   umgekehrt), der Rahmen des Feldes, der Fokus, der Satz zur Einwilligung und
   die Bestaetigung, die nach dem Absenden an dieselbe Stelle tritt. Sechs
   einzeln ueberschriebene Farben waeren sechs Stellen, an denen die naechste
   Aenderung eine vergisst.

   Die Werte sind **fest und nicht aus den Token der Seite**: Die Flaeche ist
   hell wie dunkel dieselbe, genau wie die Kachel ohne Bild - ein Blau, das im
   Dunkelmodus aufhellt, waere ein zweiter Farbwert fuer dieselbe Marke. */
.text-waldpost {
  --paper: var(--rubrik-discover);
  --strong: #fff;
  --ink: #fff;
  --soft: color-mix(in srgb, #fff 78%, transparent);
  --line: color-mix(in srgb, #fff 55%, transparent);
  background-color: var(--rubrik-discover);
  background-image: url("hoehenlinien.svg");
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
  color: #fff;
  padding: 1.7rem 1.5rem;
}
/* Die Bestaetigung sitzt schon im Kasten - ihr eigener Balken und ihr eigener
   Grund waeren ein Kasten im Kasten. */
.text-waldpost .fertig {
  border-left: 0; background: none; padding: 0; margin: 0;
}
/* **Der Satz zur Einwilligung braucht den Kasten im Selektor** - dieselbe
   Falle wie beim leisen Nachsatz: `.waldpost-recht` allein (0,1,0) verliert
   gegen `.item-text p` (0,1,1), und der Satz stand damit im Beitrag auf
   Lesegroesse und mit dem Abstand eines Absatzes im Kasten. */
.text-waldpost .waldpost-recht {
  margin: .7rem 0 0; font-size: .86rem; line-height: 1.5;
}
/* Der Platzhalter erbt die Textfarbe nicht - ohne diese Zeile setzt der
   Browser sein eigenes Grau, und das ist auf Blau ein Fleck. */
.text-waldpost ::placeholder { color: var(--soft); opacity: 1; }

/* **Die Worte im Kasten** - was zwischen `[[newsletter]]` und
   `[[/newsletter]]` steht. Sie tragen den Kasten im Selektor, aus demselben
   Grund wie der Satz zur Einwilligung darueber: `.item-text p` ist (0,1,1) und
   schlaegt jede Klasse allein.

   Die Ueberschrift steht dichter an ihrem Absatz als sonst im Text - in einem
   Kasten von wenigen Zeilen ist der Abstand einer Seitengliederung eine
   Luecke. */
.text-waldpost .waldpost-worte { margin: 0 0 1.2rem; }
.text-waldpost .waldpost-worte h2,
.text-waldpost .waldpost-worte h3 {
  margin: 0 0 .4rem; font-size: 1.2rem; line-height: 1.3; color: var(--strong);
}
.text-waldpost .waldpost-worte p {
  margin: 0 0 .7rem; font-size: 1rem; line-height: 1.6;
}
.text-waldpost .waldpost-worte > :last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------------------
   DER KALENDER - `/veranstaltungen/`
   ---------------------------------------------------------------------------

   **Eine Liste, keine zwei Darstellungen.** Am Schirm ein Monatsraster und auf
   dem Telefon eine Liste waeren zwei Bauteile fuer dieselben Daten - und das
   Raster waere die schwaechere Haelfte: Bei vier Terminen im Monat sind
   neunundzwanzig Zellen leer, und eine leere Zelle sagt „hier ist nichts", wo
   eine Liste „hier kommt das" sagt.

   **Die Zeile ist ein Satz: Tag, Sache, wann und wo.** Der Tag traegt sie und
   steht deshalb vorn in einer eigenen Spalte - wer eine Liste nach Monaten
   liest, sucht einen Tag. Rechtsbuendig, damit „3." und „24.-28." an derselben
   Kante enden und die Namen daneben eine gemeinsame Kante haben.

   **Kein Rahmen um die Zeile, nur eine Linie darunter** - dieselbe Sprache wie
   die Zeitspannen im Editor: Eine Liste gleichartiger Zeilen braucht Trennung,
   keine Kaesten. Die letzte gibt ihren Strich ab. */
/* **Der Sprung landet unter der Leiste, nicht dahinter.**

   Ohne diese Zeile scrollt der Browser die Monatsmarke exakt an den obersten
   Rand - und dort steht die Navigationsleiste. Sichtbar ist dann der erste
   Termin, die Marke ist weg, und der Klick auf das Band sieht aus wie „nichts
   passiert". Derselbe Wert wie an den Abschnitten der Prosaseiten
   (`.about-block[id]`), aus demselben Grund und mit derselben Rechnung. */
.kalender-monat { margin: 0 0 2.2rem; scroll-margin-top: calc(var(--navheight, 3.7rem) + 1.2rem); }
/* **Recurring, date open** - the section after the last month. A line above it
   sets it apart from the time axis: these rows have no place on it, they are
   the ones whose date is still to come. Their date column reads "Termin
   offen", in the quiet tone, because it is a state and not a day. */
.kalender-offen { border-top: 1px solid var(--line); padding-top: 1.6rem; }
.kalender-offen .terminzeile-wann { color: var(--soft); font-variant-numeric: normal; }
/**
 * **Der Monat ist eine Ueberschrift, keine Gruppenmarke.**
 *
 * Er sah aus wie „BEANTWORTET" im Editor - klein, gesperrt, grau, mit einer
 * Linie darunter. Zwei Dinge stimmten daran nicht. Die **Linie** stiess auf
 * die Oberkante der ersten Terminzeile (`.terminzeile a` traegt `border-top`):
 * zwei Striche im Abstand eines halben Zeilenabstands, und der zweite gehoerte
 * schon zur Zeile. Und **grau und klein** machte aus dem Monat die leiseste
 * Zeile des Kalenders, obwohl er das Fach ist, in dem alles darunter liegt.
 *
 * Jetzt ist er die Ueberschrift des Hauses - schwarz, 1,45 rem, wie „Was
 * ansteht" auf der Startseite. Gesetzt wird nur der Abstand: Die globale
 * `h2`-Regel bringt 2,6 rem nach oben mit, und die traegt hier schon der
 * Abschnitt (`.kalender-monat`).
 */
.kalender-monat h2 {
  margin: 0 0 .5rem; padding: 0;
}
/* In the guest folder the month is a divider inside a tab, not the heading
   of a page - smaller, and the sections closer together. */
#mappe .kalender-monat { margin-bottom: 1.6rem; }
#mappe .kalender-monat h2 { font-size: 1.25rem; }
/**
 * **Suche und Standort ueber der Liste** - kein Monatsband mehr. Die Suche
 * schneidet die Liste beim Tippen, der Standort schreibt die Entfernung an
 * jede Zeile (`web/kalender.js`). Die Form ist die jeder Suche im Haus - rund,
 * mit der Kante als Linie; den Radius und das Polster bringt die gemeinsame
 * Regel mit (siehe „A search box is round"), hier steht nur, was der Kalender
 * eigenmaechtig hat: der eigene Grund und die volle Breite.
 */
/* **Die Suchzeile des Kalenders ist `.searchbar`** - dieselbe Bauart wie auf
   einer Ergebnisseite: was links, wo rechts, der Rahmen an der Leiste und
   nicht am Feld. Hier steht nur, wo sie sitzt; Rundung, Fokusring, die
   Trennlinie und die Breite des Ortsknopfs kommen von dort. Ein eigenes Feld
   daneben waere eine zweite Suchzeile, die zu neun Zehnteln gleich aussieht. */
.kalender-suche { margin: 0 0 1rem; }
/* Der Satz ueber der Liste darf einen Rueckweg tragen - der Knopf darin ist ein Verweis. */
#kalender-zahl .linklike { text-decoration: underline; text-underline-offset: .2em; }


/* ---------------------------------------------------------------------------
   DIE TERMINZEILE - ein Bauteil, zwei Orte
   ---------------------------------------------------------------------------

   Unter dem Suchschlitz der Buehne und im Kalender steht dieselbe Zeile
   (`item.js terminzeile`): Bild, Zeitraum, Name, Ort - vier Spalten, eine
   Hoehe. Hier steht ihre Form **einmal**; darunter zwei Haeute: auf der
   Buehne Schrift in `--nav-ink` mit Schatten auf dem Foto, im Kalender
   Papier.

   **Die Bildspalte gehoert der ganzen Liste, nicht der Zeile** (2,75 rem,
   dasselbe Quadrat wie in den Suchvorschlaegen). Im Kalender ist sie da, auch
   wo kein Bild liegt: leer, nicht gefuellt - fiele sie je Zeile weg, staende
   das Datum an wechselnden Stellen, und eine Liste ohne gemeinsame Kante liest
   sich nicht. Auf der **Buehne** gibt es sie gar nicht (`bild: false` in
   `home.js`): Dort liegt die Liste auf einem Foto, ein zweites kleines Bild
   darauf ist ein Bild auf einem Bild - und die Kante haben dann alle Zeilen
   am Datum.

   **Der Zeitraum haelt seine Spalte** (10,5 rem, `nowrap`): Zwei Zeilen im
   Datum machen die ganze Reihe hoch. Der Name darf kuerzen (`ellipsis`, der
   volle steht im `title`), der Ort steht rechts aussen - so haben die Namen
   links eine Kante und die Orte rechts eine zweite. Untereinander gelesen ist
   das eine Tabelle ohne Kopf, und genau das soll es sein. */
.terminliste { list-style: none; margin: 0; padding: 0; }
/* **„Was ansteht" on the start page** - the same rows as the calendar, over the
   full width of its container; heading left, the location row right, as over the
   calendar. The empty state is a sentence, not a heading over nothing. */
.termine-abschnitt { margin: 3.2rem 0 0; }
.termine-kopf {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: .4rem 1.2rem; margin: 0 0 .8rem;
}
.termine-kopf h2 { margin: 0; }
.termine-ort { margin: 0; font-size: .88rem; color: var(--soft); }
.termine-ort .linklike { color: inherit; }
.termine-leer { margin: 0; color: var(--soft); }
.termine-alle { margin: .9rem 0 0; font-size: .95rem; }
/**
 * **Die Datumsspalte misst 8,7 rem, und die Zahl ist gemessen.**
 *
 * Der laengste Fall ist nicht der, den man im Bestand sieht, sondern der
 * Jahreswechsel: `31.12.26 – 01.01.27` braucht in Inter mit Tabellenziffern
 * **8,11 rem**. `22.05. – 13.09.26` sind 7,05, `25. – 28.09.26` sind 5,77, ein
 * einzelner Tag 3,63. Mit 8,7 bleibt dem schlimmsten Fall eine halbe rem Luft,
 * und die Spalte traegt trotzdem keine zweieinhalb rem Leere vor sich her.
 *
 * **Die Breite haengt an der Schrift der Zelle.** Gemessen wird im Browser,
 * mit `font-variant-numeric: tabular-nums` und der Groesse, die die Zelle
 * wirklich traegt - eine Zahl aus einer anderen Schrift ist hier eine
 * Behauptung.
 *
 * **Schmaler geht nicht, ohne etwas zu verlieren:** Die Zelle ist `nowrap`,
 * also bricht nichts um - sie liefe in den Zwischenraum und an den Namen.
 * Wer die Zahl aendert, misst vorher (`tests/kalender.test.ts` haelt die
 * Untergrenze fest).
 */
.terminzeile > a:first-child,
.terminzeile-haus > details > summary {
  display: grid; grid-template-columns: var(--thumb) 8.7rem minmax(0, 1fr) auto;
  /**
   * **Derselbe Zeilenabstand wie in der Liste der Gaestemappe** (`.7rem`, dort
   * in `.mp-liste a`). Die zwei Listen standen unter- und nebeneinander und
   * atmeten verschieden: .4 gegen .7 rem. Das ist keine Aussage ueber den
   * Inhalt, sondern zweimal dieselbe Zeile mit zwei Massen - und mit der
   * Miniatur auf 60 px war die engere ohnehin zu knapp.
   */
  gap: 0 .8rem; align-items: center;
  /* Air above and below: the picture (or its placeholder) must not touch the
     rules between the rows. Only vertical - the row starts on the text edge. */
  padding: .5rem 0;
  color: inherit; text-decoration: none;
  border-top: 1px solid var(--line);
}
.terminliste li:last-child > a:first-child { border-bottom: 1px solid var(--line); }
/**
 * **An own event of the house opens in place** (`hausTerminZeile` in
 * `mappe.js`) - the row is a `summary` with the same grid as a row link, the
 * chevron where the place stands, turned when open. The detail sits on the
 * name's vertical; the last row carries its bottom rule on the item, so the
 * rule stays under the open detail.
 */
.terminzeile-haus > details > summary { cursor: pointer; list-style: none; }
.terminzeile-haus > details > summary::-webkit-details-marker { display: none; }
.terminzeile-haus > details > summary:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* The chevron before the name - it says "this opens" where one reads. */
.terminzeile-haus .terminzeile-sache { align-items: center; gap: .3rem; flex-wrap: nowrap; }
/* Chevron and name stay on one line - on a phone the name otherwise takes a
   line of its own (`flex: 1 1 100%` in the narrow step) and drops below it. */
.terminzeile-haus .terminzeile-name { flex: 1 1 auto; min-width: 0; }
.terminzeile-auf { flex: none; color: var(--soft); display: inline-flex; }
.terminzeile-auf svg { width: 1.3rem; height: 1.3rem; transition: transform .15s ease; }
.terminzeile-haus > details[open] .terminzeile-auf svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) { .terminzeile-auf svg { transition: none; } }
/* The text of an opened event spans the whole row. */
.terminzeile-detail { padding: .2rem 0 .9rem; font-size: .95rem; }
.terminzeile-detail > :first-child { margin-top: 0; }
.terminzeile-detail p { margin: 0 0 .4rem; }
.terminliste li.terminzeile-haus:last-child { border-bottom: 1px solid var(--line); }
/**
 * **The entry an event takes place at is the place pill** - pin and name,
 * linked to the entry, where the municipality stands otherwise. The row is
 * one link to the event, and a link inside a link is invalid markup; so the
 * item is the grid, the row's link spans all of it and hands its tracks on
 * (`subgrid`), and the pill lies in the place column above the row link. A
 * click anywhere else is still the event.
 */
.terminzeile-mit-eintrag {
  position: relative; display: grid;
  /* `max-content`, not `auto`: the entry's name in the pill may shorten, so
     its min-content is next to nothing, and an `auto` track fell to 0 px. */
  grid-template-columns: var(--thumb) 8.7rem minmax(0, 1fr) max-content;
  grid-template-rows: auto; column-gap: .8rem;
}
.terminzeile.terminzeile-mit-eintrag > a:first-child {
  grid-column: 1 / -1; grid-row: 1 / -1;
  grid-template-columns: subgrid; grid-template-rows: subgrid;
}
/* The pill itself (`BFP.eintragPille`) - in a row and in the backend list. */
.terminzeile-ort-eintrag {
  display: inline-flex; align-items: center; gap: .25rem; text-decoration: none;
}
/* An entry is a way somewhere, not only a place: its word stands in the
   strong ink, not the soft grey of a plain place pill. Two classes, so it
   beats `.terminzeile-ort` further down. */
.terminzeile-ort.terminzeile-ort-eintrag { color: var(--strong); }
/* Its place in a row: the place column, above the row's link. */
.terminzeile-mit-eintrag > .terminzeile-ort-eintrag {
  grid-column: 4; grid-row: 1; align-self: center;
  position: relative; z-index: 1;
}
/* The pin takes the colour of the word - so it turns white with it where the
   customer pill fills under the pointer. */
.terminzeile-ort-eintrag .pin-icon { width: .6rem; height: .7rem; flex: none; stroke: currentColor; fill: currentColor; }
.terminzeile-ort-eintrag .terminzeile-ort-wort { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.terminzeile-ort-eintrag:hover { color: var(--strong); background: var(--line); }
/* The pill is always a link, so the pointer underlines its word - in every
   tier, on top of whatever the tier does to the surface. */
.terminzeile-ort-eintrag:hover .terminzeile-ort-wort { text-decoration: underline; }
.terminzeile-ort-eintrag:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* The colour is the paid tier. Without a contract the entry pill stays the
   grey place pill (only its word in the strong ink, because it is a way
   somewhere). PLUS: a tint of its rubric on paper with the strong ink, the
   full colour with white under the pointer. The text stays the strong ink on
   the tint: dark blue on black would be 1.4 : 1 in dark mode. */
.terminzeile-ort.terminzeile-ort-rubrik { background: color-mix(in srgb, var(--rf) 22%, var(--paper)); color: var(--strong); }
.terminzeile-ort.terminzeile-ort-rubrik:hover { background: var(--rf-voll); color: var(--auf-bild-ink); }
/* PRO: the full rubric colour with white, in rest too -
   gold reads its ink (`--rf-voll`), white on the light gold is 2.55 : 1.
   Under the pointer only the word is underlined, the colour has nowhere
   further to go. */
.terminzeile-ort.terminzeile-ort-pro { background: var(--rf-voll); color: var(--auf-bild-ink); }
/* **The event list of the backend** (`#/veranstaltungen`): date and place as
   the same monospace pills as a row outside - the date first, it is what the
   list is ordered by; the entry pill where there is one. */
.tab-pillen { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; }
.tab-pillen .terminzeile-ort { justify-self: auto; }
/**
 * **"+12" and the rest behind it** (`pillenMitRest` in `profil.js`). The
 * button is a pill like its neighbours - it counts what is missing, so it
 * wears the same shape - with the pointer of a button. The list lives in the
 * top layer (`popover`), so the browser's centring defaults are reset and the
 * script places it under the pill. Black frame like every layer of the house,
 * one line per name, rolling past 18 rem like the layer of the year band.
 */
.pillen-mehr { border: 0; cursor: pointer; font: inherit; }
.pillen-mehr:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* The rest reads like the row it belongs to: white pills on the grey of a
   hovered row - the same names, the same form, only more of them. */
.pillen-rest {
  position: fixed; inset: auto; margin: 0;
  min-width: 14rem; max-width: 24rem; max-height: 18rem; overflow-y: auto;
  padding: .5rem; list-style: none;
  color: var(--ink); background: var(--shade); border: 1px solid var(--strong);
  box-shadow: var(--card-shadow);
}
/* Only while open: an author `display` would beat the hidden state of the popover. */
.pillen-rest:popover-open { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; }
.pillen-rest li { display: flex; min-width: 0; max-width: 100%; }
.pillen-rest .terminzeile-ort {
  justify-self: auto; background: var(--card-ground);
  overflow: hidden; text-overflow: ellipsis;
}
/* The entry filter of the calendar - the same quiet sentence as the search
   count, with its way back. */
.kalender-filter { margin: 0 0 .6rem; color: var(--soft); font-size: .9rem; }
.kalender-filter[hidden] { display: none; }
/* The events on an entry page: the calendar's rows, then the way to all of
   them - the same "more" with an arrow as under a card. */
.entry-termine { max-width: var(--text); margin: 0 auto 2.2rem; }
.entry-termine .terminliste { margin: 0; padding: 0; list-style: none; }
.entry-termine-alle { margin: .8rem 0 0; }
.entry-termine-alle a { display: inline-flex; align-items: center; gap: .35rem; }
.entry-termine-alle svg { width: 1rem; height: 1rem; }
/**
 * **Die Zeile eines Nachbarorts ist dieselbe, nur ohne Datumsspalte.**
 *
 * Ein Ort hat kein Datum - also drei Spalten statt vier: Miniatur, Name,
 * Entfernung. Alles andere bleibt, was es ist (`.terminzeile`), denn die
 * zwei Listen stehen auf derselben Seite untereinander: „Was ansteht" und
 * „In der Nähe". Eine eigene Zeilenform daneben waere ein zweites Bauteil
 * fuer dieselbe Sache.
 *
 * Die Regel steht **vor** der engen Stufe, damit die ihre eigenen Spalten
 * setzen kann - gleiche Spezifitaet, und dort gewinnt die spaetere.
 */
.ortszeile > a:first-child { grid-template-columns: var(--thumb) minmax(0, 1fr) auto; }
.terminzeile-bild { width: var(--thumb); height: var(--thumb); }
/**
 * **Ohne Bild ein Platzhalter, keine Luecke.** Heller Grund, graue Kante,
 * dieselbe Rundung wie das Foto darin (`.such-bild`, 4 px) - damit die zwei
 * Zustaende dieselbe Form haben und nur der Inhalt sich unterscheidet.
 *
 * `box-sizing: border-box`, weil die Kante sonst zwei Pixel dazulegt und die
 * Spalte gegen die Zeilen mit Bild verrutscht.
 *
 * Die Farben sind Token, keine Grauwerte: Im Dunkelmodus ist `--shade` dunkel
 * und `--line` hell genug - „hellgrau" heisst hier „eine Stufe neben dem
 * Papier", und das gilt in beiden Modi.
 */
.terminzeile-bild-leer {
  box-sizing: border-box; border-radius: var(--thumb-radius);
  border: 1px solid var(--line); background: var(--shade);
  display: flex; align-items: center; justify-content: center;
}
/**
 * **Das Themenzeichen sitzt auf dem Platzhalter, in mittlerem Grau.**
 *
 * `--soft` ist das leise Grau des Hauses und geht im Dunkelmodus mit; ein
 * abgetippter Grauwert waere dort entweder unsichtbar oder zu laut. Es fuellt
 * das Feld nicht aus - ein Zeichen mit Luft ringsum liest sich als Zeichen,
 * eines bis an die Kante als abgeschnittenes Bild.
 */
.thema-icon { width: 1.35rem; height: 1.35rem; color: var(--soft); flex: none; }
.terminzeile-wann {
  font-size: .82rem; color: var(--soft);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.terminzeile-sache { min-width: 0; display: flex; align-items: baseline; gap: .5rem; }
.terminzeile-name {
  font-weight: 700; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/**
 * **Unter dem Zeiger passiert nichts** - kein Unterstrich am Namen und keine
 * Flaeche unter der Zeile.
 *
 * Der Unterstrich sass am Namen und behauptete damit, **er** sei der Verweis;
 * anklickbar ist die **ganze Zeile**. Ein leiser Grund darunter sagte das
 * richtig, war aber in einer Liste aus zwanzig Zeilen ein Flackern beim
 * Darueberfahren - und auf dem Telefon, wo diese Listen gelesen werden, gibt
 * es kein Zeigen. Der **Fokusrahmen** bleibt: Er ist der Tastaturweg und kein
 * Schmuck.
 */
.terminzeile > a:first-child:focus-visible .terminzeile-name { text-decoration: none; }
.terminzeile > a:first-child:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* „laeuft gerade" steht neben dem Namen - eine Aussage ueber die Sache, keine
   eigene Zeile. `flex-shrink: 0`, damit aus „laeuft gerade" bei einem langen
   Namen nicht „laeuft ge..." wird. */
/* **Written as `.konto-status.terminzeile-laeuft` on purpose.** With one class
   it tied with `.konto-status`, and that rule stands further down the file -
   so its grey ground, its bold and its .8rem won, and the pill was neither
   green nor small. Two classes settle it by weight instead of by line. */
.konto-status.terminzeile-laeuft {
  flex-shrink: 0;
  /* Green for "running now" - the house's state pair for live - in the
     monospace of every state the machine reports, regular weight, as small
     as the place pill beside it. */
  background: var(--state-live-bg); color: var(--state-live-ink);
  font-family: var(--mono); font-size: .68rem; font-weight: 400; letter-spacing: .04em;
  padding: .1rem .5rem;
}
/**
 * **Der Ort steht als Pille auf leiser Flaeche, in der Monospace** - dieselbe
 * Form wie die Entfernung in der Gaestemappe (`.mp-km`) und die Ortszeile im
 * Kopf der Mappe. Sie ist die **Einordnung** der Zeile und nicht ihr Inhalt:
 * Der Name traegt die Aussage, der Ort sagt, wo das liegt. Als Fliesstext
 * rechts aussen las er sich als zweiter Name.
 */
.terminzeile-ort {
  justify-self: end;
  padding: .25rem .75rem; border-radius: 999px; background: var(--shade);
  font-family: var(--mono); font-size: .68rem; color: var(--soft);
  white-space: nowrap; text-align: right;
}
/**
 * ===========================================================================
 * **Eng wird die Zeile in zwei Stufen schmaler, nicht in einer**
 * ===========================================================================
 *
 * Vier Spalten tragen sich nur, solange der Name Platz hat. Gerechnet gegen
 * die festen Teile - Bild 2,75 rem, Datum 8,5 rem, drei Zwischenraeume zu
 * .8 rem und ein Ort von rund 90 px - bleiben bei 520 px Fensterbreite
 * **rund 210 px** fuer den Namen: „SURM – Schwarzwald Ultra Radmarathon"
 * endet dort in Auslassungspunkten, waehrend rechts „Alpirsbach" steht.
 * Bequem wird der Name erst ab etwa 300 px, und das ist bei **40 rem**.
 *
 * **Stufe eins (bis 40 rem): der Ort springt in die naechste Zeile.** Datum
 * und Name bleiben zusammen, und der Name bekommt die ganze Breite, die der
 * Ort freigibt. Das ist der Tausch, der hier etwas bringt: Der Ort ist die
 * Einordnung, der Name die Sache.
 *
 * **Stufe zwei (bis 30 rem): auch das Datum bekommt seine Zeile.** Auf 360 px
 * waeren Datum und Name nebeneinander zwei Kruemel. Das Bild steht in beiden
 * Stufen links und ueber alles.
 *
 * Die Zeilen stehen **ausdruecklich** (`grid-row`), nicht im Fluss: Stufe zwei
 * erbt die Spalten von Stufe eins, und ohne eigene Angabe saessen Datum und
 * Name danach in derselben Zelle.
 * =========================================================================== */
@media (max-width: 40rem) {
  /**
   * **Zwei Zeilen, und die erste traegt die zwei kurzen Angaben.**
   *
   * Oben Datum links und Ort rechts - beide sind kurz, beide sind eine
   * Einordnung, und nebeneinander lesen sie sich als **eine** Zeile darueber:
   * wann und wo. Darunter der Name ueber die ganze Breite, denn er ist die
   * Sache und das Einzige, was wirklich lang wird.
   *
   * Vorher standen drei Angaben in drei Zeilen (Datum, Name, Ort) - der Name
   * bekam trotzdem nur seine Inhaltsbreite und war gekuerzt, waehrend rechts
   * daneben 88 px leer blieben. `flex: 1 1 100%` gibt ihm die Zeile wirklich.
   *
   * Die Zeilen stehen **ausdruecklich** (`grid-row`): Ohne eigene Angabe
   * saessen Datum und Name in derselben Zelle.
   */
  /**
   * **Das Datum bekommt seine Breite, der Ort den Rest.** Andersherum
   * (`1fr auto`) nahm der Ort seine volle Textbreite - „Villingen-Schwenningen
   * · 20,2 km" schob sich auf das Datum. Jetzt ist die Datumsspalte `auto`
   * (sie bricht ohnehin nicht um) und der Ort `minmax(0, 1fr)`: Er weicht als
   * Erster und endet in Auslassungspunkten, denn er ist die Einordnung und
   * nicht die Sache.
   */
  /**
   * **Two free rows around the text** (`1fr auto auto 1fr`), so the picture
   * spanning them does not push the name down. With two rows only, the 60 px
   * of the picture were split between them, and the gap between date and name
   * depended on the picture's height (8.3 px) - while the same row in the
   * guest folder stood at 1.5. Now the text block sits in the middle and the
   * gap is one number: `--zeile-abstand`, shared with `.mp-text`.
   */
  .terminzeile > a:first-child,
  .terminzeile-haus > details > summary {
    grid-template-columns: var(--thumb) auto minmax(0, 1fr);
    grid-template-rows: 1fr auto auto 1fr; gap: 0 .7rem;
  }
  .terminzeile-bild { grid-row: 1 / span 4; }
  .terminzeile-wann { grid-column: 2; grid-row: 2; }
  .terminzeile-ort {
    grid-column: 3; grid-row: 2; justify-self: end;
    /**
     * **`max-width: 100%` ist die Zeile, die es tut.** `justify-self: end`
     * misst das Feld an seinem Inhalt und nicht an der Spalte - ein langer
     * Ortsname wuchs deshalb nach **links** ueber das Datum hinaus, und
     * `overflow: hidden` half nicht: Es beschneidet den Inhalt im eigenen
     * Kasten, und der Kasten war schon zu breit.
     */
    max-width: 100%; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .terminzeile-sache {
    grid-column: 2 / span 2; grid-row: 3; flex-wrap: wrap; margin-top: var(--zeile-abstand);
  }
  .terminzeile-name { flex: 1 1 100%; }
    /* Narrow: the same tracks as every row - the pill stays up by the date. */
  .terminzeile-mit-eintrag {
    grid-template-columns: var(--thumb) auto minmax(0, 1fr);
    grid-template-rows: 1fr auto auto 1fr; column-gap: .7rem;
  }
  .terminzeile-mit-eintrag > .terminzeile-ort-eintrag { grid-column: 3; grid-row: 2; }
  /**
   * **Beim Nachbarort steht die Entfernung ueber dem Namen.**
   *
   * Dieselbe Bewegung wie beim Termin, nur eine Spalte weniger: Oben rechts
   * die Pille, darunter der Name ueber die ganze Breite. Die leere
   * Datumsspalte muss dabei wirklich weg - stehen bliebe sie als zweiter
   * Zwischenraum, und der Text staende einen Zwischenraum weiter rechts als
   * in der Liste darueber.
   */
  .ortszeile > a:first-child { grid-template-columns: var(--thumb) minmax(0, 1fr); }
  .ortszeile .terminzeile-ort { grid-column: 2; }
  .ortszeile .terminzeile-sache { grid-column: 2; }
}

/* ---------------------------------------------------------------------------
   MERCHANDISE - the pieces, each with its name underneath
   ---------------------------------------------------------------------------

   Squares, because the photos are square, three across on a screen and two on
   a phone, all the same size: with nine pieces any larger first tile leaves one
   alone in the last row, and it reads as a mistake. No frame and no shadow -
   the photos bring their own ground (the misty forest).

   **The text stays in the reading column, only the gallery reaches beyond it.**
   A photo is not a line: it may grow wider without the sentence next to it
   growing longer. The grid is therefore **wider than its container** and
   centred again with a negative left margin: `100%` is the reading column,
   `--galerie` the wanted width, half the difference pulls it out evenly. On a
   phone the difference is zero, and `min()` catches it.

   **The limit is the frame, not the window:** the parent is the reading column
   (`.about`), so the grid has to know the frame - `main`'s maximum width, else
   the window - to end where the header above it ends.

   **More air between rows than between columns:** at the same gap a caption
   would sit as close to the photo below as to its own and read as its title.

   **The caption is set like a card title and its meta line**, not bold (the
   house rule), the second line muted. `align-items: start` lets a name break
   onto two lines on a phone without stretching its neighbours. */
.merchpage { --galerie: 1000rem; }
.merchgrid {
  --rahmen: calc(min(100vw, var(--rahmen-breite)) - 2 * var(--inset));
  --breite: min(var(--rahmen), var(--galerie, 57rem));
  display: grid; gap: 1.6rem .8rem; margin: 2rem 0 0;
  grid-template-columns: repeat(2, 1fr);
  align-items: start;
  width: var(--breite);
  margin-left: calc((100% - var(--breite)) / 2);
}
@media (min-width: 46rem) {
  .merchgrid { grid-template-columns: repeat(3, 1fr); }
}
.merchtile { margin: 0; }
/* The handle fills the tile - `.photo-zoom` otherwise expects a cell that sets
   its height; here the photo sets it. */
.merchtile .photo-zoom { height: auto; }
.merchtile img {
  display: block; width: 100%; height: auto; aspect-ratio: 1 / 1;
  object-fit: cover; background: var(--shade);
}
.merchcaption { margin-top: .5rem; }
.merchname { display: block; color: var(--strong); font-size: 1rem; font-weight: 400; line-height: 1.25; }
.merchdetail { display: block; color: var(--soft); font-size: .88rem; margin-top: .15rem; }
/* What stands under the grid - motifs, materials, questions - starts clear of the last captions. */
.merchmore { margin-top: 3.4rem; }

/* The newsletter box between the text and the grid keeps its distance, as in
   a post text, and lies on black instead of blue (`--merch-post-ground`). */
.merchpage .text-waldpost {
  --paper: var(--merch-post-ground);
  background-color: var(--merch-post-ground);
  margin: 2rem 0 2.6rem;
}

/* Two lines in the grid; in the large view the same caption runs as one line. */
.merchtile .merchsep { display: none; }
.lightbox .merchname, .lightbox .merchdetail { display: inline; color: inherit; font-size: inherit; margin: 0; }
@media (max-width: 34rem) {
  .merchname { font-size: .95rem; }
}


/* Ab hier ist Platz für zwei Spalten: 17rem Verzeichnis, 3rem Luft und die
   Lesespalte in ihrer gewohnten Breite - zusammen 66rem, also fast der ganze
   Inhaltsrahmen. Darunter bleibt alles eine Spalte, und das Verzeichnis ist
   wieder ein Aufklapper über dem Text. */
@media (min-width: 68rem) {
  :root { --toc-offen: 1; }
  /**
   * **Das Verzeichnis steht an der linken Kante, nicht neben der Mitte.**
   *
   * Vorher war der ganze Artikel zentriert - Verzeichnis und Text rückten
   * gemeinsam in die Mitte, und links davon stand eine handbreite leere Spalte,
   * die aussah wie ein Fehler. Jetzt nimmt der Artikel den Inhaltsrahmen: Das
   * Verzeichnis beginnt dort, wo die Seite beginnt, und der Text steht daneben
   * in seiner gewohnten Breite.
   */
  .about-mitnav {
    max-width: none; margin: 0;
    display: grid; grid-template-columns: 17rem minmax(0, var(--text));
    column-gap: 3rem; align-items: start;
  }
  /* Die Überschrift steht über dem Text, nicht über beiden Spalten: Sie gehört
     zum Gelesenen und nicht zum Verzeichnis. */
  .about-mitnav > h1 { grid-column: 2; grid-row: 1; }
  /**
   * **Das Verzeichnis reicht ueber alle Zeilen daneben** (`span 99`).
   *
   * Es klebt, solange seine eigene Flaeche im Bild ist - stuende es nur in
   * Zeile 2, waere auf der Angebotsseite (Ueberschrift, Vorspann, Text) nach
   * dem Vorspann Schluss, und es wanderte nach oben aus dem Bild.
   */
  .about-mitnav > .toc {
    grid-column: 1; grid-row: 2 / span 99; margin: 0;
    position: sticky; top: calc(var(--navheight, 3.7rem) + 1.2rem);
    max-height: calc(100vh - var(--navheight, 3.7rem) - 3rem); overflow-y: auto;
  }
  /* Alles andere steht in der Lesespalte - nicht `#rechttext` beim Namen
     genannt: Die Angebotsseite hat dieselbe Form und einen anderen Knoten,
     und eine Kennung in einer Rasterregel waere die Stelle, an der die
     naechste Seite lautlos einspaltig bleibt. */
  .about-mitnav > :not(h1):not(.toc) { grid-column: 2; }
  /* Offen ist es hier immer, also braucht es keinen Griff zum Öffnen. */
  .about-mitnav > .toc > summary { display: none; }
  /**
   * **Und deshalb fällt hier auch der Rahmen weg.**
   *
   * Er beantwortet auf dem Telefon eine Frage, die sich in der Spalte nicht
   * stellt: wie weit das Verzeichnis reicht. Hier steht es allein in seiner
   * eigenen Spalte, drei Zentimeter neben dem Text - ein Kasten darum wäre eine
   * zweite Umgrenzung für eine Fläche, die schon eine hat.
   */
  .about-mitnav > .toc { border: 0; }
  /* Ohne Rahmen und ohne Griff braucht die Liste auch den Einzug nicht mehr: Es
     gibt hier keinen Pfeil, auf dessen Achse sie sich stellen müsste. Sie
     beginnt an der linken Kante der Seite, wie die Überschrift daneben. */
  .about-mitnav > .toc nav ul { padding: 0; }
}

/* **The form of the house** (sign-in, rating, pictures, profile): one column,
   one field below the other. Two columns would be shorter and worse - a form
   is read top to bottom, and every field here is a question of its own. */
.vorschlag-form { display: grid; gap: 1.4rem; margin: 2rem 0 0; }
/**
 * **Im Formular gibt der Rahmen den Abstand, nicht der Absatz.**
 *
 * Das Raster hat schon `gap: 1.4rem`. Ein `<p>` darin bringt aber seinen
 * Standardrand von rund 1em mit - und beides addiert sich: Ueber und unter
 * „Ich habe einen Code an ... geschickt" standen damit zweieinhalb Zeilen
 * Leerraum statt einer. Zwei Abstandssysteme uebereinander sind kein Abstand,
 * sondern ein Zufall.
 */
.vorschlag-form p { margin: 0; }
/* A group of fields inside the form (the guest fields on the rating page)
   keeps the rhythm of the form: the same gap between its fields, also between
   first and last name once the pair stacks on the phone. */
#gast-felder { display: grid; gap: 1.4rem; }
#gast-felder .feld-paar { row-gap: 1.4rem; }
/**
 * **Die Fusszeile eines Formulars: Knopf und Ausweg.**
 *
 * Sie hatte keine eigene Regel - der Knopf und der Verweis daneben („Andere
 * Adresse") standen als zwei Zeilenelemente mit einem Leerzeichen dazwischen
 * aneinandergeklebt. Ein Ausweg direkt an der Hauptsache liest sich wie ein
 * Teil von ihr.
 *
 * Jetzt derselbe Abstand wie zwischen zwei Knoepfen (`.actions`), und mit
 * `flex-wrap`: Auf dem Telefon nimmt der Knopf die ganze Breite, der Verweis
 * rutscht darunter.
 */
.form-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1.4rem;
}
/**
 * **`align-content: start` ist hier die ganze Loesung** (05.09.2026).
 *
 * Das war der Grund, warum zwei Felder nebeneinander unterschiedlich hoch
 * aussahen, obwohl oben **eine** Hoehe fuer alle steht.
 *
 * Ein `.feld` ist ein Raster aus zwei oder drei Zeilen: Beschriftung, Feld,
 * manchmal ein Hinweis. Steht es in einem `.feld-paar`, macht das Raster beide
 * Spalten gleich hoch - und das Feld **ohne** Hinweis bekommt damit mehr
 * Platz, als sein Inhalt braucht. Ein Raster verteilt diesen Rest auf seine
 * Zeilen: Die Beschriftung wuchs von 21 auf 34 px, die Auswahl darunter von
 * 43 auf 55. Gemessen im Editor an „Gemeinde" (mit Hinweis) neben „Region"
 * (ohne): 12,7 px Unterschied, bei 640 px Fensterbreite 22,5 px.
 *
 * Niemand hatte das geschrieben; es fiel aus der Anordnung heraus. Deshalb war
 * es auch mit einer Ausnahme je Bauteil nicht zu treffen - es haette sie an
 * jedem Paar gebraucht, in dem eine Seite einen Satz mehr hat.
 *
 * `start` heisst: Der Rest bleibt unten stehen. Die Zeilen behalten ihre
 * natuerliche Hoehe, und damit fluchten Beschriftung und Feld in beiden
 * Spalten - unabhaengig davon, was darunter noch kommt.
 */
.feld { display: grid; gap: .35rem; align-content: start; }
/**
 * **Die Beschriftung eines Feldes ist eine Frage, kein Titel** (04.09.2026).
 *
 * Sie stand in `.92rem` **fett** - bei drei Feldern nebeneinander noch in
 * Ordnung, in der Bilderschicht mit sechs Beschriftungen und zwei langen
 * Haken-Saetzen war die Schicht eine Wand aus fetter Schrift. Fett ist die
 * Auszeichnung fuer das eine Wort, das heraussticht; wenn alles fett ist,
 * sticht nichts heraus.
 *
 * Jetzt `.86rem` und **halbfett** (600): noch klar die Beschriftung, aber
 * leiser als das, was man hineinschreibt - und die Eingabe ist das, worauf es
 * ankommt.
 */
/* `legend` steht hier mit drin (05.09.2026): „Übernachten" ueber drei Haken
   ist dieselbe Sache wie „Gemeinde" ueber einem Feld - eine Beschriftung. Sie
   stand in .85rem/700 und damit als Einzige lauter als alle anderen. */
.feld > span, .feld > label, fieldset > legend { font-size: .86rem; font-weight: 600; }
/* Ein `em` in der Beschriftung („freiwillig") bleibt kursiv und wird leiser. */
.feld > span em, .feld > label em, .ed-aufklapp > summary em, .ed-gruppe > legend em {
  font-weight: 400; font-style: normal; color: var(--soft);
}
/* Feld, Auswahl und Textkasten kommen aus der Grundregel ganz oben - hier
   stand dieselbe Erklaerung ein zweites Mal, mit einem anderen Innenabstand. */
/* Der Fokus faerbt den Rahmen - die Regel steht **oben** bei den Feldern und
   gilt fuer alle, nicht nur fuer die in `.feld`. */
/* Der Hinweis steht **unter** dem Feld und nicht darueber: Er erklaert, was
   eine gute Antwort ausmacht - das liest man, wenn man ins Feld schaut, nicht
   bevor man die Frage kennt. */
.feld-hint { color: var(--soft); font-size: .85rem; line-height: 1.45; }

.ort-abschnitt { margin: 2.2rem 0 0; }
/* Die Kacheln stehen untereinander mit Luft - und ab genug Breite zu zweit,
   wie auf der Startseite. */
/* Spalten und Abstaende stehen oben, in der gemeinsamen Regel mit `#neu` und
   der Trefferliste. Hier bleibt nichts - und genau das ist die Aussage. */
/* Was kein Foto hat, steht als Zeile darunter: vollstaendig, aber ohne den
   Anschein, es waere schon eine Kachel wert. */
.ort-mehr { font-size: .9rem; margin: 1rem 0 0; }
/**
 * **Das Wort davor ist leise, nicht die erste Zeile.**
 *
 * Die Regel hing an `> span:first-child` - der Stelle und nicht der Sache.
 * In „Außerdem im Ort:" steht dort das Wort, unter „In der Nähe" der erste
 * Nachbarort: Er stand grau da, waehrend die vier daneben schwarz standen,
 * und nichts an ihm war anders. Eine Klasse sagt, was gemeint ist.
 */
.ort-mehr-wort { color: var(--soft); }

/* ---------------------------------------------------------------------------
   Die Marken: Rubrik waehlen, dann - wenn man mag - die Gattung.
   ---------------------------------------------------------------------------

   **Rund** (07.09.2026, loest "eckig, nicht rund" ab). Das ist keine neue
   Ausnahme von `border-radius: 0`, sondern die vorhandene Hausform fuer **eine
   Reihe kurzer Woerter zum Antippen**: dieselbe wie die Gattungen unter der
   Suche (`.gattungs-pillen a`) und die Suchbegriffe im Editor (`.ed-wort`).
   Genau das steht hier - und es steht direkt unter einem eckigen Suchfeld, in
   dessen Form es sich eckig als weiteres Formularstueck las statt als Auswahl.
   Drei Reihen derselben Sorte mit zwei Formen waeren zwei Bedienungen, die man
   einzeln lernt.

   Die gewaehlte Marke bleibt **gefuellt**, die anderen tragen nur ihre Linie:
   Der Unterschied ist eine Flaeche, nicht eine Schattierung, und damit auch auf
   einem hellen Schirm im Freien zu sehen.

   **Beide Reihen sind gleich gross.** Die zweite war kurz kleiner, damit sie
   als Verfeinerung liest - und das war falsch: Zwei Reihen mit zwei Groessen
   sehen aus wie zwei verschiedene Bauteile, und das Auge sucht den Unterschied
   im Wort statt in der Zeile. Dass die zweite Reihe zur ersten gehoert, sagt
   ihre Stellung darunter und die Tatsache, dass sie nur erscheint, wenn oben
   etwas gewaehlt ist. */
.pills {
  display: flex; flex-wrap: wrap; gap: .4rem;
  margin: 1rem 0 0;
}
/**
 * **So hoch wie der Umschalter daneben** (`--regler-hoehe`) - dieselbe Zahl
 * wie bei den Gattungspillen und den Rubrikfeldern. Auf einer Seite, auf der
 * drei Sorten Bedienteil untereinander stehen, sind drei Hoehen drei Bauteile;
 * das Polster steht deshalb nur noch waagerecht, die Hoehe kommt aus dem
 * Token.
 */
.pill {
  font: inherit; font-size: .88rem; line-height: 1.2;
  min-height: var(--regler-hoehe); padding: 0 .9rem;
  background: none; color: var(--ink);
  border: 1px solid var(--line); border-radius: 999px;
  cursor: pointer;
  display: inline-flex; align-items: center; gap: .4rem;
}
.pill:hover { border-color: var(--strong); color: var(--strong); }
.pill:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* Gefuellt, aber **nicht fett**: Die Flaeche sagt schon, welche Marke gilt.
   Ein Schriftschnitt dazu aendert die Breite des Wortes, und die Reihe rueckt
   bei jedem Antippen ein Stueck - eine Bewegung, die nichts bedeutet. */
.pill.is-on {
  background: var(--strong); border-color: var(--strong); color: var(--paper);
}
.pills-sub { margin-top: .5rem; }

/* Die Suchzeile auf der Ortsseite: dieselbe Form wie in der Suche, aber der Ort
   ist hier keine Wahl - er ist die Seite. Deshalb eine Angabe, kein Knopf. */
.ort-bestand .searchbar { margin-top: .4rem; }
.ort-bestand .searchbar-place { cursor: default; }
.ort-bestand .searchbar-place:hover { color: var(--strong); }
.ort-mehr a { color: var(--ink); }
.ort-mehr a:hover, .ort-mehr a:focus-visible { color: var(--accent); }

/* ===========================================================================
   DAS MAGAZIN  (09.09.2026)
   ===========================================================================

   Zwei Seiten, und beide teilen dieselbe Aufteilung wie `/merchandise/`:
   **Text in der Lesespalte, Bilder ueber die ganze Breite.** Ein Absatz ueber
   1100 px ist ueber hundert Zeichen lang, ein Foto in der Lesespalte ist ein
   Foto in Briefmarkengroesse.

   Gebraucht werden dafuer genau zwei neue Namen. Alles andere ist da: `.hero`,
   `.about`, `.lead`, `.count`, `.item-text`, `.results`, `.card`. Ein eigenes
   Aussehen fuer Beitraege waere ein zweites Regal im selben Haus. */
#magazin > h1,
#magazin > .count {
  max-width: var(--text);
}

/* **Eine Achse, und zwar die mittlere.**

   Unter dem Primaerbild steht der Inhalt **zentriert**: Das Bild geht ueber die
   ganze Rahmenbreite, der Text bleibt in der Lesespalte (46 rem) - und ein
   Textblock, der unter einem breiten Bild an der linken Kante klebt, laesst das
   Bild schief aussehen. Eine Mittelachse haben beide gemeinsam.

   Es gilt fuer **alles unter dem Bild**, nicht nur fuer den Text: Vorspann,
   Text, Fragen. Sonst haette die Seite zwei Achsen, und die Naht zwischen
   Erzaehltem und Verzeichnis (die Linie ueber den Fragen und den Orten) begaenne
   an der einen und endete an der anderen.

   **Das Kachelraster der Orte bleibt auf der ganzen Breite** - es ist die
   Fortsetzung des Bildes, nicht des Textes. Seine Ueberschrift steht mittig wie
   der Text darueber, weil sie zum Text gehoert: Sie sagt, was der Beitrag mit
   dem Guide zu tun hat.

   **Hier steht keine Regel**, und das ist die Auskunft: `.about` steht von
   sich aus mittig (`margin: 0 auto`), und `--text` deckelt die drei Bloecke
   darunter bei ihrer eigenen Regel. Eine Zeile, die die Vorgabe wiederholt,
   liest sich beim naechsten Mal als Absicht, an der etwas haengt. */
/* ---------------------------------------------------------------------------
   DAS PRIMAERBILD EINES BEITRAGS: 4 ZU 3
   ---------------------------------------------------------------------------

   Am Eintrag ist das Kopfbild ein **Streifen** (21 zu 9): Dort ist es die
   Zierleiste ueber einer Auskunft, und darunter kommt sofort die Sache -
   Adresse, Zeiten, Karte.

   Am Beitrag ist es das **Bild**. Es ist dasselbe, das die Kachel im Magazin
   traegt, und wer aus der Liste hierher kommt, soll es wiedererkennen; ein
   Streifen ist ein anderer Ausschnitt derselben Aufnahme. 4 zu 3 ist dafuer
   das Verhaeltnis: hoch genug, dass ein Motiv darin steht, und nicht
   quadratisch - eine Seite ist breiter als hoch, ein Bild darauf auch.

   **Und es ist wesentlich breiter als die Bilder im Text.** Die stehen in der
   Lesespalte (46 rem), dieses steht auf der Rahmenbreite. Das ist die
   Rangfolge, und sie liegt in der Breite - nicht in einem Rahmen und nicht in
   einer Beschriftung. */
/* **Ohne `>`**: Das Bild steht seit dem 21.09.2026 **im** `article`, unter
   dem Kopf - also nicht mehr als direktes Kind von `#beitrag`. Mit dem
   Kindselektor traf die Regel nichts mehr, und das Bild fiel auf 21 zu 9
   zurueck: ein Streifen statt des Ausschnitts, den die Kachel im Magazin
   zeigt. Lautlos, wie jeder Selektor, der ins Leere greift. */
#beitrag .hero .photo img { aspect-ratio: 4 / 3; }
/* Luft zwischen Vorspann und Bild und zwischen Bild und Text - `.hero`
   bringt unten 1,2 rem mit, oben nichts, und oben schloss der Vorspann
   sonst direkt an die Bildkante an. */
#beitrag .hero { margin: .4rem 0 2rem; }

/* **Das Anmeldefeld im Text** (10.09.2026) - es steht in der Lesespalte wie
   ein Absatz, nicht ueber die ganze Breite: Ein Formular ist eine Handlung im
   Text und kein Bild. Luft davor und danach, damit es sich als eigener Schritt
   liest; das Formular selbst bringt sein Aussehen aus der Huelle mit
   (`.waldpost`), hier steht nur, **wo** es steht. */
#beitrag .item-text > .text-waldpost { margin: 2rem auto; }

/* ---------------------------------------------------------------------------
   **EIN BILD IM TEXT GEHT ÜBER DIE GANZE BREITE**  (10.09.2026)
   ---------------------------------------------------------------------------

   Ein Foto in der Lesespalte (46 rem) ist ein Foto in Briefmarkengröße - und
   auf einer Seite, deren Kopfbild 1060 px breit ist, sieht es aus wie ein
   Versehen. Was **allein** in einem Absatz steht (`.text-bild`) und was als
   **Satz** steht (`.gallery`), bekommt deshalb die Rahmenbreite, wie das
   Kopfbild darüber.

   **Der Kasten wächst, die Zeilen bleiben.** Nicht die Bilder brechen aus der
   Spalte aus, sondern der Kasten geht auf die volle Breite und die **Absätze**
   behalten `--text`. Der andere Weg wären negative Ränder und eine Rechnung
   gegen `100vw` - und `vw` zählt die Rollleiste mit: Genau daran saß die
   Merchandise-Galerie einmal sieben Pixel zu weit links. Dieselbe Lösung wie
   bei der Infobox im Bilderraster: Ein Rahmen ist eine Kante, ein Satz ist
   eine Zeile.

   **Ein Bild neben einem Absatz bleibt in der Spalte** - es gehört zum Text,
   nicht über ihn. */
#beitrag > .about { max-width: none; }
#beitrag > .about > .rubrik,
#beitrag > .about > h1,
#beitrag > .about > .lead,
#beitrag > .about > .item-mehr,
#beitrag .item-text > p,
#beitrag .item-text > h2,
#beitrag .item-text > h3,
#beitrag .item-text > ul,
#beitrag .item-text > ol,
#beitrag .item-text > blockquote,
#beitrag .item-text > .text-nachsatz,
#beitrag .item-text > .text-waldpost,
#beitrag .item-text > .text-bild-neben {
  max-width: var(--text);
  margin-inline: auto;
}
/* Und der Textkasten selbst deckelt nicht mehr - er trägt jetzt beides. */
#beitrag > .about > .item-text { max-width: none; }

/* ---------------------------------------------------------------------------
   **DER KOPF STEHT AUF EINER ACHSE**  (21.09.2026)
   ---------------------------------------------------------------------------

   Rubrik, Datum, Ueberschrift und Vorspann - mittig, wie der Kopf einer
   Eintragsseite (`.item-ident`). Sie sagen, **was das ist**, und mittig gesetzt
   bilden sie einen Block, den man in einem Blick liest; darunter kommt das
   Bild, und ein Bild hat keine Zeilenanfaenge, an denen sich ein
   linksbuendiger Kopf ausrichten koennte.

   **Der Langtext bleibt linksbuendig**, und das ist keine Inkonsequenz: Dort
   sind es Absaetze, und ein mittig gesetzter Absatz liest sich schlecht, weil
   jede Zeile woanders anfaengt. Derselbe Schnitt wie am Eintrag
   (`#entry .item-body .lead` mittig, `.item-text` nicht). */
#beitrag > .about > h1,
#beitrag > .about > .lead {
  text-align: center;
}
/* The section line is a flex column like on an entry page; standing alone in
   the article it is a block that centres itself. */
#beitrag > .about > .rubrik { max-width: var(--text); margin: 0 auto .6rem; }


/* ===========================================================================
   DAS BILDERRASTER  (09.09.2026)
   ===========================================================================

   **Bei Bildern ist das Bild die Auskunft.** Eine Zeile zeigte sechs
   Zentimeter Text und einen Daumennagel; wer „welches nehme ich" beantworten
   will, las Dateinamen. Das Raster zeigt die Bilder und schreibt den Nachweis
   darunter - dieselbe Reihenfolge wie ueberall (Inhalt vor Technik), nur passt
   der Inhalt hier in ein Rechteck statt in eine Zeile.

   **Ein Raster, drei Flaechen**: der Reiter „Bilder" eines Eintrags, die
   Kerndaten eines Beitrags - und wo sonst noch Bilder gewaehlt werden. Die
   Kachelbreite ist deshalb keine Zahl, sondern ein `minmax`: In der Lesespalte
   stehen zwei, im breiten Reiter vier.

   **Der gewaehlte Zustand ist ein Rahmen** und keine Farbe - dasselbe Mittel
   wie am Primärbild-Stern, und es traegt auch fuer den, der Farben nicht
   unterscheidet. Eckig wie alles hier. */
.ed-bildraster {
  list-style: none; margin: 1.2rem 0 0; padding: 0;
  display: grid; gap: .9rem;
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
}
.ed-bildkachel {
  position: relative;
  display: grid; gap: .35rem; align-content: start;
  padding: .4rem;
  border: 1px solid var(--line); background: var(--paper);
}
/* Der Knopf **ist** das Bild - er hat keinen eigenen Rand und keinen eigenen
   Grund, sonst waere die Kachel zweimal gerahmt. */
.ed-bildkachel-auf {
  display: block; width: 100%; padding: 0;
  border: 0; background: none; cursor: pointer;
}
.ed-bildkachel-fremd { cursor: default; }
/* Der Griff zieht die Kachel - der Browser zieht gar nichts. Ein `img` ist von
   Haus aus ziehbar, und wer die Kachel am Foto fasste, startete den nativen
   Bildzug: Der verschluckt die Zeigerereignisse und den Klick danach, also
   ordnete sich nichts und die Schicht ging auch nicht auf. Das Attribut am
   Bild schaltet es ab, diese Zeile faengt die Browser, die es ueber CSS
   loesen. */
.ed-bildkachel-bild {
  display: block; width: 100%; aspect-ratio: 3 / 2;
  object-fit: cover; background: var(--line);
  -webkit-user-drag: none; user-select: none;
}
.ed-bildkachel-auf:hover .ed-bildkachel-bild { opacity: .9; }
.ed-bildkachel:has(.ed-bildkachel-auf:focus-visible) {
  outline: 2px solid var(--strong); outline-offset: 2px;
}
.ed-bildkachel-auf:focus-visible { outline: none; }
.ed-bildkachel[data-gewaehlt] {
  border-color: var(--strong);
  box-shadow: inset 0 0 0 1px var(--strong);
}
/* Ein abgelehntes Bild ist auch als Bild leiser - dieselbe Entscheidung wie in
   der Zeile davor. */
.ed-bildkachel[data-status="rejected"] .ed-bildkachel-bild { opacity: .55; }

/* Der Nachweis, wie er draussen unter dem Foto steht - er ist die Kontrolle,
   wegen der es diesen Reiter gibt. Er darf umbrechen, auch mitten im Wort: In
   9,5 rem passt kein Name mit Jahr in eine Zeile. */
.ed-bildkachel-wort {
  margin: 0; display: grid; gap: .15rem;
  font-size: .74rem; line-height: 1.3;
  overflow-wrap: anywhere;
}
/* Der Nachweis kuerzt in der **Zeile** mit einer Ellipse - dort ist die Breite
   knapp und der Rest steht daneben. In der Kachel ist die Breite die Kachel:
   Gekuerzt bliebe „© Lena Bauer · 2025 · C…" stehen, und die Rechtegrundlage
   ist der Teil, wegen dem der Nachweis dasteht. Also umbrechen. */
.ed-bildkachel-wort .ed-bildnachweis {
  font-size: inherit; white-space: normal; overflow: visible; text-overflow: clip;
}
.ed-bildkachel-her { color: var(--soft); }
.ed-bildkachel-wort .konto-status { justify-self: start; }

/* **Ein Knopf in der Ecke des Bildes** - der Stern oben rechts, die Ecke, in
   der im Haus jede Entscheidung sitzt (das X einer Schicht, das ⓘ am Foto),
   und der Griff oben links, sein Gegenstueck. Eine Regel fuer Lage, Mass und
   Grund; der eigene Grund haelt beide auf jedem Foto lesbar - eine Entscheidung
   fuer hell und dunkel statt zwei.

   **Das Mass ist 1,9 rem und nicht 2,8** (17.09.2026). Gemessen an der Kachel,
   fuer die es gebaut ist: Im vierspaltigen Reiter ist das Foto 158 x 106 px,
   und zwei Quadrate zu 45 px deckten davon **ein Viertel** zu. Jetzt sind es
   30 px und rund ein Zehntel - das Foto ist die Auskunft, wegen der es dieses
   Raster gibt.

   **Ohne unsichtbare Vergroesserung.** Ein `::before` auf 44 px brachte den
   Daumen zurueck und naehme dem Knopf darunter genau den Rand, an dem man ihn
   trifft - und das Uebereinander von Ziehen und Bearbeiten war der gemeldete
   Fehler. Was man sieht, ist hier das Ziel. */
.ed-bildkachel-eck {
  position: absolute; top: .6rem;
  background: var(--paper);
}
.ed-bildkachel-stern { right: .6rem; }
/* Der Griff zieht - und nur er. `touch-action: none` liegt deshalb auf diesen
   45 px und nicht auf der Kachel: Auf der Kachel naehme es dem Telefon das
   Rollen. Immer sichtbar, nicht erst beim Zeigen - er ist das einzige Zeichen
   dafuer, dass die Reihenfolge etwas bedeutet, und was man nur beim
   Darueberfahren findet, findet nur, wer schon weiss, dass es da ist. */
.ed-bildkachel-griff {
  left: .6rem;
  display: grid; place-items: center;
  width: 1.9rem; height: 1.9rem; padding: 0;
  border: 0; color: var(--soft); cursor: grab;
  touch-action: none;
}
.ed-bildkachel-griff svg { width: .95rem; height: .95rem; }
.ed-bildkachel-griff:hover { color: var(--strong); }
.ed-bildkachel-griff:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
.ed-bildkachel.sort-zieht .ed-bildkachel-griff { cursor: grabbing; }

/* Die letzte Kachel ist das Ablegefeld - in der Groesse eines Bildes, damit
   die Reihe nicht springt. `.ablage` bringt Rahmen und Zeichen mit; hier
   bekommt sie nur das Mass. */
.ed-bildkachel-neu { border-style: dashed; }
.ed-bildkachel-neu .ablage {
  margin: 0; min-height: 0; height: 100%;
  aspect-ratio: 3 / 2; border: 0; padding: .5rem;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .3rem; text-align: center;
}
.ed-bildkachel-neu .ablage-satz { margin: 0; font-size: .78rem; line-height: 1.3; }
.ablage-leise { color: var(--soft); }

/* ---------------------------------------------------------------------------
   DIE DETAILSCHICHT EINES BILDES
   ---------------------------------------------------------------------------

   **Das Bild oben, ueber die ganze Breite - die Angaben darunter, auf
   derselben.** Das ist die Reihenfolge, in der man es liest: erst was zu sehen
   ist, dann was dazugehoert.

   Zwei Spalten (18 rem Bild links, Felder rechts) hatten das Bild auf
   Daumennagelgroesse und die Felder auf 24 rem - genau verkehrt fuer eine
   Flaeche, deren einzige Frage "stimmt das an diesem Bild" ist. Ein
   Alternativtext beschreibt, was man sieht; man muss es sehen koennen.

   66 rem und nicht die 34 der Grundform: Diese Schicht ist keine Rueckfrage,
   sondern ein Arbeitsplatz. 96vw deckelt sie auf dem Telefon.

   **Der Einzug faellt weg.** In der Zeile richtete er das Formular auf die
   Bildkante der Kopfzeile darueber aus; in der Schicht gibt es keine Kopfzeile
   mit Pfeilspalte, und der Einzug waere ein Rand ohne Grund. */
#ed-bildschicht { width: min(66rem, 96vw); }
#ed-bildschicht .schicht-inhalt { max-width: none; }
#ed-bildschicht .ed-zeileform {
  background: none;
  padding: 0;
  /* **Immer eine Spalte.** Die Breite gehoert dem Bild, nicht der Aufteilung. */
  grid-template-columns: 1fr;
}

/* **Der Deckel ist eine Hoehe, kein Seitenverhaeltnis.** 3 zu 2 auf 66 rem
   sind 704 px - damit stuende der Alternativtext unter der Fensterkante, und
   die Schicht rollte, bevor man etwas getippt hat. Der Ausschnitt wird
   beschnitten (object-fit: cover), nicht gestaucht; der Punkt, den man klickt,
   bleibt derselbe Anteil des Bildes. */
#ed-bildschicht .ed-schnitt img { max-height: 46vh; }

/* Die Angaben nehmen die Breite mit - aber nicht als eine Spalte 66 rem
   breiter Felder: Ein Textfeld, das breiter ist als der Text darin lang, ist
   eine Flaeche ohne Auskunft. Also zwei Spalten, und quer darueber das, was
   ein Ganzes ist: der Alternativtext (er ist ein Satz), die Pruefnotiz und die
   Knopfreihe. */
@media (min-width: 52rem) {
  #ed-bildschicht .ed-bildfelder {
    grid-template-columns: 1fr 1fr;
    column-gap: 1.4rem;
  }
  /* Quer steht der Alternativtext - **benannt und nicht abgezaehlt**: Mit
     `:first-child` waere die Regel richtig, solange er oben steht, und still
     falsch, sobald jemand die Reihenfolge aendert. Er ist ein Satz und
     braucht die Zeilenlaenge; die Erlaubnisnotiz daneben ist eine Notiz und
     steht deshalb in ihrer Spalte. Und quer stehen die Pruefnotiz und die
     Knopfreihe: Sie gehoeren zum Ganzen, nicht zu einer Spalte. */
  #ed-bildschicht .ed-bildfelder > label.feld:has(textarea),
  #ed-bildschicht .ed-bildfelder > .pruef-grund,
  #ed-bildschicht .ed-bildfelder > .pruef-knoepfe { grid-column: 1 / -1; }
}


/* ---------------------------------------------------------------------------
   ZWEI BREITEN: DAS KOPFBILD UND DIE BILDER IM TEXT
   ---------------------------------------------------------------------------

   **Das Kopfbild nimmt den ganzen Rahmen** (1100 px) - es steht vor der
   Ueberschrift, vertritt den Beitrag und ist dasselbe Bild, das in der Liste
   die Kachel traegt. Es liegt deshalb **ausserhalb** der Lesespalte, direkt in
   `main`, und braucht dafuer keine eigene Regel.

   **Die Bilder im Text bleiben in der Lesespalte.** Sie gehoeren zu dem
   Absatz, unter dem sie stehen - „der Sneaker von der Seite" unter dem
   Abschnitt, der ihn beschreibt. Ueber die volle Breite gesetzt waeren sie
   genauso gross wie der Aufmacher, und dann sagt die Groesse nichts mehr: Der
   Rang eines Bildes ist seine Breite, und wenn alle gleich breit sind, gibt es
   keinen.

   Hier stand die Regel andersherum (`min(var(--galerie), …)`, also volle
   Rahmenbreite) - dieselbe Breite wie das Kopfbild. Sie stehen jetzt in der
   Spalte, in der auch der Text steht, und das ist die Aussage. */
.text-bild { margin: 1.8rem 0; }
/* **And it keeps its own shape** - measured on the Playmobil page (09.09.2026):
   the packshot of the recipe is 2560 x 2165, and the 3:2 crop that every
   `.photo img` gets took **21 % of its height** away. The same argument as for
   an image beside a paragraph, only here it is even stronger: an image standing
   alone in a text is the one the author chose to show whole - often a graphic,
   and with a graphic the crop is the message.

   A tile in a set stays 3:2: there the equal shape **is** the row.

   This needs the edge lengths in the markup (`mediaQuellen` returns them),
   otherwise the box is unknown until the file arrives and the text below jumps
   down. */
.text-bild .photo img { aspect-ratio: auto; }

/* **Das Video mitten im Text** (`item.js VIDEO_MARKE`) - derselbe Rahmen wie am
   Eintrag (`.videoblock`), nur mit dem Abstand eines Bildes im Text statt dem
   eines Abschnitts. `.videoblock` traegt seinen eigenen unteren Abstand fuer
   die Eintragsseite; hier zaehlt der Rhythmus der Absaetze, also wird er
   zurueckgesetzt und der Aussenabstand steht am Traeger.

   In der Lesespalte und nicht breiter: Ein Video ist hier dasselbe wie ein
   Bild, das allein im Text steht - es gehoert zu dem Absatz darueber. */
.text-video { margin: 1.8rem 0; }
.text-video .videoblock { margin: 0; }

/* ---------------------------------------------------------------------------
   **EIN BILD NEBEN DEM ABSATZ**

   Zeichen vorn, Text dahinter (`item.js RICHTEXT_BILD_VORN`). Kein Umfluss,
   sondern zwei Spalten: Ein Float laesst den Text unter dem Bild weiterlaufen
   und zieht bei einem kurzen Absatz die **naechste** Ueberschrift neben das
   Bild - dann steht dort etwas, was nicht dazugehoert. Zwei Spalten hoeren da
   auf, wo der Absatz aufhoert.

   13 rem fuer das Bild: In der Lesespalte (46 rem) bleiben damit rund 30 rem
   Text, und das sind noch 60 Zeichen je Zeile. Breiter waere das Bild kein
   Beistand mehr, sondern die Hauptsache - dafuer gibt es die Figur ueber die
   ganze Textbreite.

   **Der Preis, offen:** Ein hochkantes Bild neben einem kurzen Absatz laesst
   rechts unten Luft. Das ist die Folge der Entscheidung gegen den Umfluss, und
   sie ist die richtige: Luft ist harmlos, eine Ueberschrift an der falschen
   Stelle nicht.

   Auf dem Telefon untereinander - 13 rem neben 8 rem Text waeren zwei Spalten,
   in denen keine Zeile steht. */
.text-bild-neben {
  display: grid;
  grid-template-columns: minmax(0, 13rem) 1fr;
  gap: 1.2rem;
  align-items: start;
  margin: 1.8rem 0;
}
/* Der Abstand gehoert dem Block, nicht dem Absatz darin - und das Bild bringt
   seinen eigenen mit (`.photo { margin: 1.2rem 0 }`), den es hier nicht braucht. */
/* Die rechte Spalte traegt den Absatz **und** den leisen Nachsatz darunter -
   deshalb ein Behaelter und nicht ein `p`. */
.text-bild-neben > .text-bild-satz > p { margin: 0 0 .6rem; }
.text-bild-neben > .text-bild-satz > p:last-child { margin-bottom: 0; }
.text-bild-neben .photo { margin: 0; }
/* **Und es behaelt seine eigene Form.** Ueberall sonst gilt Querformat
   (`.photo img { aspect-ratio: 3/2; object-fit: cover }`) - dort sind es
   Kacheln in einer Reihe, und die gleiche Form **ist** die Reihe. Hier steht
   ein Bild allein neben einem Absatz, und es ist oft eine **Grafik**: Bei einer
   Grafik ist der Zuschnitt die Nachricht - beschnitten fehlt die Haelfte der
   Aussage, und zwar die oben. Nachgemessen an der Gewinnspielgrafik (1080 ×
   1350): Von „WIN WIN WIN" blieben zwei. */
.text-bild-neben .photo img { aspect-ratio: auto; }

/* ---------------------------------------------------------------------------
   **DIE WEITERLEITUNGEN: EINE ZEILE BRICHT NICHT UM**

   In dieser Tabelle stehen **Adressen**, und eine umgebrochene Adresse liest
   sich als zwei. Sie ist damit breiter als der Bildschirm - und genau dafuer
   steht sie in `.tab-rollt`: Der Kasten rollt quer, die Seite nicht.

   Die Spalte der Kaestchen ist so schmal wie ihr Inhalt und mittig - ein
   Kaestchen linksbuendig in einer 3rem-Spalte sieht aus wie vergessen. */
#weiterleitungen td, #weiterleitungen th { white-space: nowrap; }
.tab-wahl { width: 1%; text-align: center; }

/* ---------------------------------------------------------------------------
   **DER LEISE NACHSATZ** (`> ` im Text)

   Teilnahmeschluss, Preisangabe, Bedingung: Der Satz gehoert dazu, steht aber
   nicht auf derselben Lautstaerke. Dieselben zwei Werte, mit denen das Haus
   ueberall leise spricht (`--soft`, .82rem) - und **kein** Balken links: Der
   gehoert dem Zitat im Buchtext, und ein Zeichen mit zwei Lesarten ist eines
   zu viel.

   **Linksbuendig, ueberall.** Er steht auf derselben Kante wie der Absatz
   darueber - eine Zeile, die einzeln ausgerichtet ist, liest sich als eigenes
   Element und nicht als Nachsatz zu dem, was darueber steht.

   **Kleiner als `.count`** (.75 statt .82 rem): Der Zaehler im Backend steht
   allein in einer Zeile, dieser Satz steht **unter** einem Absatz in Lesegroesse
   - und der Abstand zwischen den zwei Groessen ist das, was ihn leise macht.

   **Die zwei Behaelter stehen im Selektor, und das ist Absicht.**
   `.text-nachsatz` allein (0,1,0) verliert gegen `.item-text p` (0,1,1) - die
   Schrift blieb auf 16,32 px, also genau auf Lesegroesse, und der Nachsatz war
   kein Nachsatz. Mit dem Behaelter davor (0,2,0) gewinnt die Regel **ohne** sich
   auf die Reihenfolge im Stylesheet zu verlassen. Es sind die beiden Orte, an
   denen `richtext` landet: der Text eines Eintrags oder Beitrags (`.item-text`)
   und der einer Ergebnisseite (`.editorial-text`). Ein dritter braucht hier
   eine Zeile - Spezifitaet schlaegt Absicht, also steht die Absicht da. */
.item-text .text-nachsatz,
.editorial-text .text-nachsatz { color: var(--soft); font-size: .75rem; line-height: 1.5; }
@media (max-width: 34rem) {
  .text-bild-neben { grid-template-columns: 1fr; }
}

/* Die Fragen unter dem Text - dieselbe Naht wie zu den Orten darunter. */
.beitrag-fragen {
  margin: 2.8rem 0 0;
  padding-top: 1.6rem;
  border-top: 1px solid var(--line);
}
.beitrag-fragen > h2 { margin: 0 auto 1.2rem; max-width: var(--text); }
/* **Eine Frage ist so breit wie eine Frage** - dieselben 46 rem wie am
   Eintrag, wo die FAQ in `.editorial` steht. Sie liefen hier auf die volle
   Rahmenbreite, weil der Abschnitt keinen Deckel hatte: eine Antwort mit
   hundertzwanzig Zeichen je Zeile, unter einem Text, der bei sechzig
   umbricht. Zwei Textbreiten auf einer Seite sind eine zu viel.

   **Der Deckel sitzt an der Frage, nicht am Abschnitt.** Die Linie oben ist
   die Naht zwischen dem Erzaehlten und dem Verzeichnis (wie bei
   `.beitrag-orte`) und geht ueber die ganze Breite - eine Naht, die auf
   halber Strecke aufhoert, trennt nichts. */
.beitrag-fragen > .qa { max-width: var(--text); margin-inline: auto; }

/* Die Orte unter dem Text. **Die Linie ist die Naht** zwischen dem Erzaehlten
   und dem Verzeichnis - hier hoert der Beitrag auf und faengt der Guide an. */
.beitrag-orte {
  margin: 2.8rem 0 0;
  padding-top: 1.6rem;
  border-top: 1px solid var(--line);
}
.beitrag-orte > h2 { margin: 0 auto 1.2rem; max-width: var(--text); }

/* ---------------------------------------------------------------------------
   Die Buehne der Startseite: Foto ueber die volle Breite, darunter die
   Einleitung auf schwarzem Grund - dazwischen eine schraege Kante.
   --------------------------------------------------------------------------- */

/* **Die Navigation liegt ueber dem Bild** - und bleibt klebend, wie sie war.
   Nicht sie wird aus dem Fluss genommen, sondern die Buehne zieht sich um die
   Hoehe des Blocks nach oben: Damit beginnt das Bild an der Oberkante, der Block
   liegt darauf (er hat den hoeheren z-index), und beim Scrollen verhaelt er sich
   unveraendert. `--navheight` misst `chrome.js` beim Aufbau. */
.has-stage .stage { margin-top: calc(-1 * var(--navheight, 3.7rem)); }
/* Der Block bleibt schwarz, auch auf einem dunklen Bild - so entschieden am
   03.09.2026. Eine Umkehrung nach Bildhelligkeit war gebaut und ist wieder
   entfernt: Ein Kopf, der je Seite die Farbe wechselt, ist unruhiger als ein
   dunkler Block auf einem dunklen Foto. Die Marke ist schwarz. */
/* Den Kopf mit der Beizeile gibt es nicht mehr: "Besondere Orte. Echte
   Erlebnisse. / Von Lokals fuer Lokals" stand ueber jeder Seite und schob dabei
   das Bild nach unten. Der Claim steht jetzt dort, wo er hingehoert - in der
   Buehne der Startseite. */

/* Die Buehne endet ohne Abstand nach unten, **wenn ein Abschnitt mit Flaeche
   folgt** - sonst bliebe ein weisser Streifen zwischen Bild und Flaeche. Steht
   darunter Text (Ortsseiten), bleiben die zwei Zeilen Luft. */
.stage { margin: 0 0 2rem; }
/* Vollflaechig heisst hier wirklich vollflaechig: Das Bild darf aus der
   Inhaltsspalte heraus. Ueber `height` statt `aspect-ratio` gesteuert, damit ein
   breiter Bildschirm keinen zwei Meter hohen Streifen bekommt. */
.stage .hero { margin: 0; }
.stage .hero .photo img {
  /* **Volle Fensterhoehe** (so entschieden am 03.09.2026; davor 88vh, 78, 62).
     Das Bild ist der Eingang, nicht die Illustration darueber.

     `dvh` und nicht `vh`: Auf dem Telefon zaehlt `vh` die Adressleiste mit, die
     beim Scrollen verschwindet - das Bild waere beim Laden hoeher als der Schirm
     und wuerde danach springen. `dvh` misst, was wirklich zu sehen ist; die
     `vh`-Zeile bleibt als Rueckfall fuer aeltere Browser stehen. */
  aspect-ratio: auto; object-fit: cover;
  /**
   * Die Hoehe ist **Fensterhoehe plus Schraege** - und das ist gerechnet, nicht
   * geschaetzt.
   *
   * Die schwarze Flaeche liegt um 5vw ueber dem Bild und ihre Oberkante steigt
   * nach rechts: Links faengt das Schwarz an der Bildunterkante an, **rechts
   * schon 5vw darueber**. Bei genau 100dvh Bildhoehe ragt der Keil dort also in
   * den ersten Bildschirm - man sieht die Schraege, bevor man gescrollt hat.
   *
   * Um 5vw hoeher liegt der hoechste Punkt des Schwarz genau auf der Kante des
   * Fensters: Der erste Bildschirm ist ganz Bild, die Schraege beginnt darunter.
   */
  height: calc(100vh + 5vw);
  height: calc(100dvh + 5vw);
}
.stage { position: relative; }
/* ---------------------------------------------------------------------------
   **DIE BUEHNE DER STARTSEITE** (`.stage-start`)
   ---------------------------------------------------------------------------

   Das Foto fuellt das Fenster, und eine **Tanne steht darin**: Ueber der linken
   Seite des Bildes liegt eine weisse Flaeche, deren rechte Kante das **rechte
   Profil des Signets** ist - der Wipfel an der Oberkante des Fensters, der
   Stammfuss an der Unterkante. In der Flaeche steht der Claim; der Rest des
   Fensters ist Foto.

   | | |
   |---|---|
   | **Die Kante ist gerechnet, nicht gemalt** | `scripts/baum-maske.py` liest `assets/logos/signet.svg` und laeuft dessen rechte Haelfte vom Wipfel bis zum Stammfuss ab. Die Marke **ist** damit die Kante: Wer das Signet aendert, aendert die Buehne, und niemand zeichnet eine zweite Tanne nach |
   | **Zwei Stuecke, ein Rand** | die flache Flaeche (`.baum-grund`, ein Anteil der Fensterbreite) und die Kante daneben (`.baum-flaeche`, ein Anteil der Fenster**hoehe**). Getrennt, weil beide verschiedenen Massen folgen: Die Flaeche soll mit der Breite wachsen, die Tanne ihr Verhaeltnis behalten |
   | **Ein Kasten von 1000 x 1000, gestreckt** | `preserveAspectRatio="none"`. Das Verhaeltnis steht damit an **einer** Stelle (`--baum-aspekt`) und nicht in den Zahlen des Pfades |
   | **Gestaucht wird sie nie** | Die Breite ist immer `Fensterhoehe x --baum-aspekt` - es gibt keinen zweiten Faktor, der sie schmaler zoege. Eine Tanne mit anderem Verhaeltnis ist eine andere Tanne, und das Signet hat genau eines. Auf dem Telefon ist sie damit fast die ganze Flaeche (301 px von 390), und die flache Kante davor schrumpft auf einen Streifen - siehe unten |
   | **Der Strich der Kontur steht am Element** | `vector-effect: non-scaling-stroke`. Der Kasten wird gestreckt, und ohne die Angabe traegt die Linie an jeder Fenstergroesse ein anderes Gewicht |
   | **Ueberlaufend abgeschnitten** | `overflow: hidden`. Bei einem hohen, schmalen Fenster ist `--baum-weiss` plus Kante breiter als das Fenster; abgeschnitten wird die Tanne dann rechts, und genau das soll dort passieren |

   **Der offene Preis:** Die Flaeche liegt im Bildkasten, den es nur mit
   Buehnenbild gibt. Ohne Foto steht auf der Startseite weder die Tanne noch
   der Claim in ihr - der Textblock traegt die Seite dann allein
   (`home.js stageStartMarkup`). */
/**
 * **Die Grundstellung ist die kompakte Fassung: nur die Zeichen.**
 *
 * Die Kante nimmt ihre Breite aus der **Hoehe** des Fensters, das Wort neben
 * dem Zeichen braucht Breite. Auf einem hohen, schmalen Fenster ziehen die
 * zwei gegeneinander, und das Wort verliert: Bei 768 x 1024 sind Kante 365 px
 * und Spalte 176 px, und "UEBERNACHTEN" (119 px bei 0,9 rem) lief links aus
 * dem Bild.
 *
 * Deshalb steht das Wort da, **wo das Fenster mindestens so breit ist wie
 * hoch** - und nicht ab einer Breite. Eine reine Breitenschwelle beantwortet
 * die falsche Frage: 768 px sind breit genug fuer ein Wort und zu schmal fuer
 * ein Wort neben dieser Tanne.
 */
.stage-start {
  /* Breite geteilt durch Hoehe des rechten Profils - die Ausgabe von
     `scripts/baum-maske.py`, dieselbe Zahl wie `BAUM.aspekt` in `home.js`. */
  --baum-aspekt: .3563;
  /* **Die flache weisse Flaeche vor der Kante.** Kompakt ist sie ein Streifen
     von 5 rem: Die Astspitzen reichen bei 390 x 844 bis 381 px von 390 und
     beruehren den rechten Rand fast. Was vom Bild bleibt, ist das, was
     zwischen den Aesten liegt - ein Keil, kein Streifen. */
  --baum-weiss: 5rem;
  --buehne-hoehe: 100vh;
  --buehne-hoehe: 100dvh;
  --baum-kante: calc(var(--buehne-hoehe) * var(--baum-aspekt));
  /* The column the claim stands in, and its margin. On the wide screen it
     reaches into the fir (see the large version below); on the phone the
     claim stands in the flat strip alone (`.stage-satz`). */
  --baum-spalte: calc(var(--baum-weiss) + var(--baum-kante) * .25 - var(--baum-versatz));
  --baum-rand: 1rem;
  /* **Wie weit die Spalte von ihrer gerechneten Lage nach links rueckt.** Er
     steht als eigene Angabe da und nicht als Zahl im `calc`: Die Lage der
     Spalte ist gerechnet (kompakt aus der Kerbe, am Schirm aus der Stammachse),
     der Versatz ist eine Entscheidung ueber das Aussehen - und die beiden
     gehoeren auseinandergehalten. */
  --baum-versatz: 30px;
  /* Der Platz am Fuss, den die Maus braucht - ohne Maus keiner. */
  --baum-fuss: 0px;
}
/* **Die grosse Fassung braucht drei Dinge, und alle drei stehen in der
   Bedingung.**

   | | |
   |---|---|
   | **Breite fuer den Claim** | `min-width: 59rem`. Die 59 rem sind die Breite, bei der auch noch **Foto uebrig bleibt**: Im schlechtesten Fall eines quadratischen Fensters nimmt die Kante 0,3563 der Breite, und `B - 480 - 0,3563 B > 120` ergibt 932 px |
   | **Ein Fenster, das nicht hochkant steht** | `min-aspect-ratio: 1/1`. Die Kante nimmt ihre Breite aus der **Hoehe**; bei 768 x 1024 sind das 365 px, und von der Flaeche bliebe nichts. Eine reine Breitenschwelle beantwortet die falsche Frage |
   | **Hoehe fuer den Claim** | `min-height: 30rem`. Ein Claim ueber drei Zeilen in 2,25 rem sind rund 125 px; dazu Leiste (59) und Maus (80) |

   **Die Flaeche waechst nicht mit dem Fenster**, sie steht auf 34 rem. Was ein
   breiteres Fenster dazugewinnt, bekommt das Foto - und das ist der Inhalt.
   Dieselbe Regel wie beim Sprachwaehler, nur strenger: eine Auswahl mit fuenf
   Zeilen raeumt keinen 27-Zoeller leer. */
/* **The tablet step: the surface comes back, narrower.**

   Between the phone and the large version stands a window that is wide
   enough for the claim next to the fir, but not for 34 rem of white plus the
   fir plus photo - a tablet, upright or lying, and a narrow laptop window.
   There the claim stays in the surface instead of breaking below the photo:

   | | |
   |---|---|
   | **From 48 rem wide and 30 rem high, in any orientation** | the large version also asks for a window that does not stand upright; here the surface takes its width from what is left, so an upright tablet works too |
   | **The surface is what the photo leaves** | `100vw - Kante - 18rem`, between 10 and 26 rem: at least 18 rem of the window stay for fir and photo beside the white. At 768 x 1024 that is the floor (10 rem), at 900 x 700 about 23 rem. It moves with the window - this is the step in between, the anchored 34 rem start with the large version |
   | **The claim one fixed step smaller** | 2.1 rem instead of 3.5 - a step, not a size that follows the window |

   The large version below overrides every value, so the two never mix. */
@media (min-width: 48rem) and (min-height: 30rem) {
  .stage-start {
    --baum-weiss: clamp(10rem, 100vw - var(--baum-kante) - 18rem, 26rem);
    --baum-spalte: calc(var(--baum-weiss) + var(--baum-kante) * .35);
    --baum-rand: 1.5rem;
  }
  .stage-start .stage-satz { font-size: 2.1rem; }
}
@media (min-width: 59rem) and (min-aspect-ratio: 1/1) and (min-height: 30rem) {
  .stage-start {
    /**
     * **34 rem, fest - die Tanne steht, wo sie steht.**
     *
     * Hier stand `clamp(30rem, 32%, 40rem)`. Die 32 % erreichen den Boden bei
     * **1500 px**: Darunter hielt der Boden, darueber wuchs die Flaeche mit
     * dem Fenster und schob die Kante nach rechts. Wer am Fensterrand zog, sah
     * die Tanne an dieser einen Stelle losfahren - eine Bewegung ohne Anlass,
     * und zwar genau dort, wo die meisten Schirme stehen.
     *
     * Fest heisst: Die Buehne ist links **verankert**, und was ein breiteres
     * Fenster dazugewinnt, bekommt das Foto. Das ist auch die Antwort auf die
     * Frage, die der Deckel von 40 rem loesen sollte - er ist damit weg.
     *
     * **Die Breite der Tanne haengt weiter an der Hoehe** (`--baum-kante`):
     * Ein hoeheres Fenster bekommt eine breitere Tanne, denn sie reicht vom
     * Wipfel bis zum Fuss. Das ist keine Ausnahme, sondern dieselbe Regel.
     */
    --baum-weiss: 34rem;
    /**
     * **Die Spalte reicht in die Tanne hinein - damit der weisse Rand links
     * und rechts gleich aussieht.**
     *
     * Die flache Flaeche endet an der Wipfellinie, die **sichtbare** weisse
     * Flaeche aber nicht: Rechts davon steht der Baum, und der ist auf der
     * Hoehe des Inhalts weiss. Mittig in der flachen Flaeche gesetzt, stand
     * der Block deshalb optisch links - 40 px Rand links, ueber 200 px rechts.
     *
     * **0,35 der Kante - gerechnet ist die Grenze, entschieden der Wert.** Im
     * Band, in dem der Satz steht, laeuft die Kante zwischen 0,42 und
     * 0,93 ihrer Breite; die **Grenze** setzt die tiefste Kerbe dieses Bandes
     * bei 0,387 - was darueber hinausragt, liegt irgendwann auf dem Foto.
     * 0,35 bleibt darunter und ist **gemessen**: Ab 720 px Fensterhoehe laeuft
     * der Claim damit in drei Zeilen (bei 0,2 waren es vier); nur das
     * kleinste Fenster dieser Fassung (944 x 600) bricht noch in vier.
     */
    --baum-spalte: calc(var(--baum-weiss) + var(--baum-kante) * .35);
    /* The margin of the column on the wide screen. */
    --baum-rand: 2rem;
  }
}
.stage-start .stage-bild { position: relative; overflow: hidden; }
/* **Volle Fensterhoehe, glatte Unterkante.** Die Hoehe war einmal
   `74dvh + 5vw`: Darunter kam die schwarze Flaeche mit ihrer Schraege, und von
   der sollte die erste Zeile noch auf den ersten Bildschirm. Die Buehne ist
   jetzt das Fenster, der Textblock beginnt darunter. */
.stage-start .hero .photo img { height: var(--buehne-hoehe); }

/* Die weisse Flaeche - flacher Teil und Kante nebeneinander, zusammen ein
   Stueck: Der Wischer beim Aufschlagen laeuft ueber **beide** und braucht
   dafuer einen Kasten. */
/* **One pixel past the bottom edge**, for the white and its line alike: on
   an iPad `100dvh` is often a fractional height, the stretched drawing ends
   on half a pixel, and the browser smooths that row - one line of photo shone
   through below the trunk. The stage clips it (`overflow: hidden`), so the
   smoothed row lies outside. Both boxes grow by the same pixel, so the line
   stays on the edge. */
/* **Surface and line are half transparent, as one layer** - from the first
   stroke of the line on. The opacity sits on the layer and not on the two
   pieces: each at .5, the inner half of the line over the surface would add
   up to .75 and stand as a lighter band along the edge. One layer is
   composited once, so surface and line are the same .5 of white. The claim
   lies outside it (`.baum-inhalt`) and stays fully opaque. */
.baum-ebene {
  position: absolute; inset: 0; z-index: 2;
  opacity: .5; pointer-events: none;
}
.baum {
  position: absolute; inset: 0 auto -1px 0; z-index: 2;
  width: calc(var(--baum-weiss) + var(--baum-kante));
}
/* **Ein Pixel Ueberlappung.** Die flache Flaeche endet dort, wo der Pfad der
   Kante bei x = 0 beginnt - bei einer gebrochenen Pixelbreite (46 % von 390
   sind 179,4) kantenglaettet der Browser beide Raender, und zwischen zwei
   weissen Flaechen stand eine graue Haarlinie ueber die ganze Fensterhoehe. */
.baum-grund {
  position: absolute; inset: 0 calc(var(--baum-kante) - 1px) 0 0;
  background: var(--paper);
}
.baum-flaeche {
  position: absolute; top: 0; right: 0; display: block;
  height: 100%; width: var(--baum-kante);
  fill: var(--paper);
}
/* Die Kontur liegt genau auf der Kante der Flaeche - und sie **bleibt
   stehen**. Sie gehoert damit nicht nur dem Aufschlagen, sondern der Kante: Die
   Haelfte des Strichs liegt auf der weissen Flaeche und ist dort nicht zu
   sehen, die andere Haelfte steht auf dem Foto und macht aus der Schnittkante
   eine **gezeichnete** Kante. Sie verlosch einmal am Ende des Wischers, und
   genau das sah aus wie ein Fehler: Erst wird eine Linie gezogen, dann ist sie
   weg.

   **Ohne Schatten**, und das ist die Ausnahme von "was auf einem Foto steht,
   traegt einen": Der Schatten gilt einem Zeichen, das **stehen bleibt** und
   sich auf jedem Bild behaupten muss. Diese Linie steht 1,5 Sekunden und
   verlischt dann; ein Schatten machte aus einem Strich ein Objekt, das sich
   vom Bild abhebt - gemeint ist aber, dass die Marke das Bild **schneidet**.
   Auf einem sehr hellen Foto ist sie dafuer kurz schwach zu sehen, und das ist
   der offene Preis. */
.baum-kontur {
  position: absolute; top: 0; left: var(--baum-weiss); z-index: 3;
  height: calc(100% + 1px); width: var(--baum-kante);
  fill: none; stroke: var(--auf-bild-ink); stroke-width: 2;
}
/* **In dark mode the line takes the colour of the surface** - as in light
   mode, where the white line and the white surface are one. White on the dark
   surface drew a second edge beside the first. */
:root[data-theme="dark"] .baum-kontur { stroke: var(--paper); }

/**
 * **Die Spalte steht zwischen Leiste und Maus, nicht in der Mitte des
 * Fensters.**
 *
 * Mittig gesetzt (`top: 50%`) lag sie unter der Navigation und unter der Maus,
 * sobald das Fenster flach wurde: Bei 844 x 390 standen **zwei von fuenf
 * Rubriken ausserhalb des Bildes** - unsichtbar, unklickbar, ohne Hinweis
 * darauf. Zwischen den zwei Kanten gesetzt kann das nicht mehr passieren, und
 * zwar ohne dass irgendwo eine Hoehe gerechnet wird: Der Kasten ist der Platz,
 * der da ist, und die Spalte sitzt mittig **darin**.
 *
 * `--navheight` misst `chrome.js` beim Aufbau, `--baum-fuss` ist der Platz der
 * Maus - null, wo es keine gibt.
 */
.baum-inhalt {
  position: absolute; z-index: 4; left: 0;
  top: var(--navheight, 3.7rem); bottom: var(--baum-fuss);
  width: var(--baum-spalte);
  /* **Spalte und nicht Zeile.** Als Zeile (`flex-direction: row`, die Vorgabe)
     bekam der Platz der Zeichen nur seine Inhaltsbreite und sass links - das
     `align-items: flex-end` der Liste darin richtete sie dann an **seiner**
     Kante aus statt an der der Spalte, und die Achse wanderte mit der Laenge
     des laengsten Wortes. Als Spalte dehnt er sich auf die Breite, und die
     Kante ist wieder eine Angabe. */
  display: flex; flex-direction: column; justify-content: center;
  padding: 0 var(--baum-rand);
}

/* ---------------------------------------------------------------------------
   **THE CLAIM IN THE WHITE SURFACE**
   ---------------------------------------------------------------------------

   The claim is the `h1` of the start page and the only thing in the white
   surface - the sentence one reads first; below on paper stands only the
   introduction.

   | | |
   |---|---|
   | **Left-aligned** | it starts on the left edge of the column, like every text block of the house; centred, a sentence over three lines starts at three places |
   | **The size does not change with the window** | 3.5 rem, bold, fixed - four lines from 944 to 2560 px wide. The column grows with the height of the window; a size that grew with it would break differently at every width |
   | **On the phone it stands above the introduction** | the white surface gives way there, so the fir moves left and more of the photo shows. The `h1` stays in the surface for screen readers and search engines (the values of `.visually-hidden`); a copy marked `aria-hidden` stands above the introduction (`.stage-claim-kompakt`) - one heading, spoken once |
   | **No signs** | the four categories and the magazine stand in the navigation, in the search layer and as pills below the search; on the stage the sentence says what this is | */
.stage-satz {
  margin: 0; color: var(--strong);
  font-size: 3.5rem; font-weight: 700; line-height: 1.15;
  text-align: start; text-wrap: balance;
}
@media (min-width: 59rem) and (min-aspect-ratio: 1/1) and (min-height: 30rem) {
  .stage-start .stage-satz { font-size: 3.5rem; }
  /* **Here it carries the text colour:** the surface is 30 rem wide, and the
     middle of the window lies on it up to 86 rem - see the calculation at
     `.stage-weiter`. */
  .stage-start .stage-weiter { color: var(--strong); }
}
/* **On the phone the claim stands above the introduction.** The compact
   version is everything the tablet step's condition does not cover - one
   negated query, so the two can never both apply or both miss. The white
   surface carries nothing there, so it gives way: no flat strip, and the
   fir's edge meets the **bottom right corner of the search square**.

   That is computed, not tried: the first segment of the edge runs from
   (0, 0) to (871.1, 366.3) in the 1000 box, and the edge is 0.3563 of the
   stage height wide - so at the height of the bar it stands at
   0.3563 x 0.8711 / 0.3663 = 0.8473 x `--navheight`, whatever the window.
   The square is `--navheight` wide; the flat white strip in front of the
   fir takes the rest, 0.1527 x `--navheight` - a strip and not a shift, so
   no sliver of photo shows left of the trunk. The `h1` in the surface stays for screen readers and search engines;
   the visible claim is the copy above the introduction. */
@media not all and (min-width: 48rem) and (min-height: 30rem) {
  .stage-start {
    --baum-weiss: calc(var(--navheight, 3.7rem) * .1527);
  }
  .stage-start .stage-satz {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    margin: -1px; padding: 0; border: 0;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
  }
  /* Claim over lead: the lead one step smaller, so the two do not compete. */
  .stage-start .stage-lead { font-size: 1.15rem; line-height: 1.5; }
}
/* The copy of the claim above the introduction exists for the phone only -
   from the tablet step on the claim stands in the white surface. */
@media (min-width: 48rem) and (min-height: 30rem) {
  .stage-claim-kompakt { display: none; }
}


/* ---------------------------------------------------------------------------
   **DAS AUFSCHLAGEN: BILD, KONTUR, FLAECHE, INHALT**
   ---------------------------------------------------------------------------

   Vier Takte in 2,2 Sekunden, und jeder setzt an, wo der vorige aufhoert:

   | Takt | Was |
   |---|---|
   | 0 - 0,3 s | **das Foto steht ganz da.** Ein Atemzug, sonst ist die Bewegung der erste Eindruck und nicht das Bild |
   | 0,3 - 1,2 s | **die Kontur baut sich nach unten auf** - von der Spitze bis zum Fuss |
   | 1,2 - 1,85 s | **die weisse Flaeche wischt nach links** - sie beginnt an der Kante, die eben gezeichnet wurde, und nimmt das Bild bis zum Fensterrand mit |
   | 1,65 - 1,85 s | **die Kontur verlischt**, waehrend der Wischer sie einholt - nicht davor: Dann stuende einen Moment lang gar nichts da |
   | 1,7 - 2,2 s | **der Claim kommt** |

   | | |
   |---|---|
   | **Der Ruhezustand ist der fertige** | jede Animation laeuft mit `backwards` und beschreibt nur ihren **Anfang**. Ohne Bewegung (`prefers-reduced-motion: reduce`) gibt es keine einzige Regel davon, und die Buehne steht fertig da - kein `forwards`, das einen Endzustand behaupten muesste |
   | **Die Kontur wird beschnitten, nicht gestrichelt** | `clip-path` statt `stroke-dasharray`. Der Strich laeuft ueber eine Zickzacklinie, und eine Strichelung waere linear in der **Bogenlaenge** - der Aufbau liefe an einem langen Ast schnell und an einer kurzen Kerbe langsam. Beschnitten ist er linear in der Hoehe, und genau das heisst "baut sich nach unten auf" |
   | **Nur `clip-path`, `opacity` und `transform`** | keine Angabe, die Platz kostet. Die Abnahme misst CLS, und eine Einblendung, die Layout bewegt, faellt dort durch |
   | **Sie laeuft einmal** | die Seite ist gebaut, das Skript zeichnet die Buehne nicht neu. Ein zweites Mal saehe man sie nur nach einem Neuladen, und genau das ist gemeint */
@keyframes baum-zeichnen {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(0 0 -2% 0); }
}
/* Von der Kante bis zum Fensterrand: Der linke Einzug geht von 100 % auf 0,
   die sichtbare Flaeche waechst also von rechts nach links. Das `-1%` am Ende
   ist die Rundung - bei genau 0 blieb an manchen Breiten eine Haarlinie. */
@keyframes baum-wischen {
  from { clip-path: inset(0 0 0 100%); }
  to   { clip-path: inset(0 0 0 -1%); }
}
@keyframes baum-inhalt { from { opacity: 0; transform: translateY(.8rem); } }
@keyframes baum-auftauchen { from { opacity: 0; } }
@media (prefers-reduced-motion: no-preference) {
  .baum-kontur { animation: baum-zeichnen .9s .3s linear backwards; }
  .baum { animation: baum-wischen .65s 1.2s cubic-bezier(.4, 0, .2, 1) backwards; }
  .baum-inhalt { animation: baum-inhalt .5s 1.7s ease-out backwards; }
  /* **Die Maus kommt mit den Zeichen.** Sie liegt ueber allem (`z-index: 4`)
     und stand die ersten 1,85 s als grauer Umriss auf dem Foto - `--soft` auf
     dunklem Laub sind rund 1,5 : 1, und dort sah sie nicht aus wie ein Hinweis,
     sondern wie ein Rest. Eigene Regel und nicht dieselbe wie `.baum-inhalt`:
     Die verschiebt mit `translateY(-50%)` und wuerde die Maus aus ihrer Lage
     nehmen. */
  .stage-weiter { animation: baum-auftauchen .5s 1.7s ease-out backwards; }
}

/* **Die Maus - immer mittig, und die Farbe folgt dem Grund.**
   ---------------------------------------------------------------------------

   Sie steht in der Mitte des Fensters, in beiden Fassungen: Der Weg nach unten
   gilt der ganzen Seite, nicht der weissen Spalte.

   **Was hinter ihr liegt, muss sie nicht raten - die Seite weiss es**, und
   zwar aus einer Rechnung: Die Mitte liegt auf dem Foto, wenn `0,5 x Breite`
   rechts vom Stamm steht, also `> --baum-weiss + 0,283 x Kante`. Mit der Kante
   bei `0,3563 x Hoehe` wird daraus `0,5 B - 0,1009 H > --baum-weiss`.

   | Fassung | Flaeche | Rechnung | Farbe |
   |---|---|---|---|
   | **kompakt** | keine, die Kante trifft die Ecke unten rechts am Suchquadrat | immer erfuellt | **weiss**, sie steht auf dem Foto |
   | **Reihe, unter 86 rem** | 34 rem (544 px) | im Quadrat erst ab 1363 px erfuellt | **Schriftfarbe**, die Mitte liegt noch auf der weissen Flaeche |
   | **Reihe, ab 86 rem** | dieselbe | erfuellt | **weiss** |

   Die Regel sieht dreiteilig aus und ist eine: Sie haengt allein an
   `--baum-weiss`. Kompakt gibt es keine Flaeche, und die Fenstermitte
   liegt weit rechts davon; in der Reihenfassung ist sie 34 rem breit und holt
   die Mitte wieder ein.

   **Kein Schatten.** Er war der Ersatz dafuer, dass ein Strichzeichen ohne
   Flaeche sich auf einem Bild nicht behaupten kann; hier steht sie nie auf
   etwas, von dem man nicht weiss, was es ist. Der offene Preis: Am Fuss eines
   sehr hellen Fotos steht sie leise da. Das war einmal `mix-blend-mode:
   difference` - eine Angabe statt einer Fallunterscheidung, und auf mittlerem
   Grau gab die Umkehrung wieder mittleres Grau: Am Fuss der Buehne, wo ein
   grauer Weg liegen kann, war sie damit **unsichtbar**. */
.stage-weiter {
  display: none; position: absolute; z-index: 4;
  left: 50%; bottom: 2.2rem;
  transform: translateX(-50%); width: 2.4rem; height: 2.4rem; padding: .2rem;
  color: var(--auf-bild-ink);
}
/* **Nur bei feinem Zeiger - und nur, wenn sie Platz hat.** Unter 30 rem
   Fensterhoehe stiesse der Claim in sie hinein. */
@media (pointer: fine) and (min-height: 30rem) {
  .stage-start { --baum-fuss: 5rem; }
  .stage-start .stage-weiter { display: block; }
}
.stage-weiter:hover, .stage-weiter:focus-visible { opacity: .7; }
.stage-weiter:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
/* **Ab hier holt die Mitte das Foto wieder ein** - siehe die Rechnung oben. */
@media (min-width: 86rem) and (min-aspect-ratio: 1/1) and (min-height: 30rem) {
  .stage-start .stage-weiter { color: var(--auf-bild-ink); }
}
.stage-maus { display: block; width: 100%; height: 100%; }
/* **Das Rad der Maus bewegt sich** - 1,6 s, nach unten und ausblendend - nur
   unter `no-preference`. Der Ruhezustand ist die stehende Maus. */
@media (prefers-reduced-motion: no-preference) {
  .stage-maus-rad { animation: maus-rad 1.6s ease-in-out infinite; }
}
@keyframes maus-rad {
  0%, 20% { transform: translateY(0); opacity: 1; }
  60% { transform: translateY(5px); opacity: .2; }
  61% { transform: translateY(0); opacity: 0; }
  100% { transform: translateY(0); opacity: 1; }
}

/* **Kompakt steht die Tanne auf fast der ganzen Breite.** 0,3563 mal
   Fensterhoehe sind auf 844 px **301 px**; mit der flachen Flaeche von 3 rem
   reichen die Astspitzen bis 349 px von 390.

   | | |
   |---|---|
   | **Die Zeichen stehen in der Tanne, nicht davor** | Am Schirm haengen sie an der Wipfellinie, kompakt liegen sie darueber. Gerechnet: Die tiefste Kerbe im Band der fuenf liegt bei 157 px, die Zeichen enden bei 76 - was unter ihnen liegt, ist dieselbe weisse Flaeche und nicht das Foto |
   | **Vom Foto bleibt ein Keil und alles zwischen den Aesten** | Die Astspitzen reichen bis 349 px, die tiefste Kerbe nur bis 157 |
   | **Kein Wort neben dem Zeichen** | dafuer ist in 5,75 rem kein Platz. Es bleibt im Dokument (`.visually-hidden`), sonst waere jedes Zeichen ein Verweis ohne Namen |
   | **Die Maus faellt weg** | `pointer: coarse`. Auf dem Telefon endet das Bild ohnehin dort, wo der Daumen schiebt | */

/* Der Verweis auf den Eintrag steht auf der **schwarzen Flaeche**, rechts und
   klein - nicht am Bildrand. Auf einem Foto, das fast den Bildschirm fuellt,
   waere er ein Aufkleber; auf der Flaeche darunter ist er eine Fussnote, und
   genau das ist er.

   Das ⓘ dagegen gehoert an den **Bildrand unten rechts**: Es zeigt auf das Bild,
   nicht auf den Eintrag. (Auf einer Kachel sitzt es oben, weil dort unten der
   Titel liegt - hier liegt dort nichts.) */
/* Das ⓘ gehoert an den **unteren Bildrand** - aber ueber die Schraege hinaus:
   Die schwarze Flaeche schiebt sich um 5vw ueber das Bild, und dort unten war es
   verdeckt. Der Abstand rechnet die Ueberlappung mit, statt sie zu schaetzen. */
/**
 * **Auf einer Buehne steht das ⓘ unten rechts.**
 *
 * Oben ist der Platz vergeben: Dort liegt die Navigation (die Buehne schiebt
 * sich unter sie, `has-stage`), und auf der Startseite dazu der Suchschlitz.
 * Ein Zeichen unter dem Navigationsblock waere ein Zeichen, das man nicht
 * findet - und auf dem Telefon eines, das unter „Menue" liegt.
 *
 * Der Abstand nach unten haelt Abstand von der **Schraege**: Auf der
 * Startseite schneidet die schwarze Flaeche 5vw hoch ins Bild, auf der
 * geteilten Buehne 6vw (Telefon) beziehungsweise nichts (Schirm, dort ist die
 * Schraege senkrecht an der linken Kante). Gerechnet statt geraten, damit die
 * Flaeche das Zeichen nicht verdeckt.
 *
 * Auf einer **Kachel** oder in der Galerie bleibt es oben: Dort ist das Bild
 * klein, und unten steht die Beschriftung.
 */
/**
 * **Ein Abstand, zwei Kanten** (17.09.2026) - `--credit-inset` gilt rechts wie
 * unten, und zwar von der **sichtbaren** Bildkante aus.
 *
 * Die schwarze Flaeche schiebt sich ueber den unteren Bildrand, und wie weit,
 * haengt an der Fensterbreite (`5vw`). Der Abstand nach unten war eine feste
 * Zahl - also wanderte das Zeichen mit jeder Breite naeher an die Kante und
 * verschwand irgendwann darunter. Gemessen auf der Ortsseite: bei 360 px blieben
 * 11 px, bei 520 px noch 3, **ab etwa 600 px war das ⓘ angeschnitten**. Genau
 * das sieht man nicht beim Bauen, sondern auf einem Telefon.
 *
 * `--stage-overlap` ist die Ueberdeckung, und sie steht dort, wo sie entsteht:
 * am Bauteil, das sie macht. Ohne sie ist sie `0px` - nicht `0`, denn `calc()`
 * braucht eine Einheit.
 */
.stage {
  --credit-inset: 1rem;
  --stage-overlap: 0px;
}
/* Die Startseite hat keine Ueberdeckung mehr: Die Buehne endet an der
   Unterkante des Fensters, der Textblock beginnt darunter. Das ⓘ sitzt damit
   1 rem ueber der Bildkante wie auf jeder anderen Buehne. */
.stage .photo .credit-chip {
  top: auto;
  right: var(--credit-inset);
  bottom: calc(var(--stage-overlap) + var(--credit-inset));
}
/**
 * **Das ⓘ auf der Buehne sitzt 1 rem von der Kante** - naeher am Rand als der
 * Knopf „Menü" darueber, der 1,8 rem vom Blockrand steht (1,25 rem Block plus
 * 0,55 rem Knopf). Die zwei stehen damit **nicht** auf einer Linie; das ist so
 * entschieden und kein Versehen.
 *
 * Nur auf der Buehne. Auf einer Kachel oder in der Galerie waere selbst das zu
 * viel: Dort ist das Bild klein, und der Rand waere ein Sechstel seiner
 * Breite. Der Wert steht als `--credit-inset` weiter oben, und er gilt an
 * beiden Kanten - `scripts/abnahme.ts` misst nicht die Zahl, sondern die
 * **Gleichheit** der zwei Abstaende, haelt also auch bei einem anderen Wert.
 */

/* Der Verweis steht **ueber der Ueberschrift** und sagt, was er bedeutet: Ein
   Name allein ("Donauquelle") beantwortet nicht, warum er dort steht. */
.stage-from {
  display: flex; align-items: center; gap: .35rem;
  margin: 0 0 1.2rem; font-size: .85rem;
  color: color-mix(in srgb, var(--nav-ink) 65%, transparent);
}
/* Der Pin ist hier hell - er liegt auf der schwarzen Flaeche, nicht auf Weiss. */
.stage-from .pin-icon { stroke: currentColor; fill: currentColor; }
/* Pin und Ortsname bleiben zusammen - ein Umbruch darf sie nicht trennen. */
.stage-place { display: inline-flex; align-items: center; gap: .3rem; white-space: nowrap; }
/* Die Linie ist eine **Unterstreichung**, kein Rahmen: Ein Rahmen, der beim
   Zeigen dicker wird, veraendert die Hoehe der Box - und der Text darunter
   springt. Eine Unterstreichung liegt ausserhalb des Layouts. */
.stage-from a {
  color: var(--nav-ink);
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .22em;
}
.stage-from a:hover, .stage-from a:focus-visible { text-decoration-thickness: 2px; }

/* Der schwarze Grund mit der schraegen Oberkante. Die Kante steigt von links
   unten nach rechts oben - dieselbe Richtung wie die Zweige im Signet. Sie
   ueberlappt das Bild um ihre eigene Hoehe, damit oben kein weisser Keil steht. */
/**
 * **Der Textblock der Startseite steht auf Papier** - Herkunftszeile und
 * Einleitung, sonst nichts; der Claim steht in der weissen Flaeche darueber.
 *
 * Er trug einmal den schwarzen Grund mit den Hoehenlinien und eine schraege
 * Oberkante. Beides gehoerte zum **Schnitt zwischen Foto und Flaeche**: Die
 * Schraege war die Kante, an der das Bild endete, und das Muster machte aus
 * dem Schwarz eine Flaeche der Marke. Den Schnitt macht jetzt die Tanne, und
 * die Buehne endet an der Unterkante des Fensters - eine Schraege von Weiss
 * auf Weiss ist eine Kante, die niemand sieht.
 *
 * **Umgeschrieben werden die Token, nicht die Kinder** (dieselbe Bauart wie
 * `.card`): `--nav` und `--nav-ink` gelten in diesem Teilbaum anders, und
 * damit stimmen Herkunftszeile, Verweis und Einleitung mit, ohne dass an
 * jedem eine Farbe steht.
 */
.stage-start .stage-text {
  --nav: var(--paper);
  --nav-ink: var(--ink);
  margin-top: 0;
  /**
   * **Oben 7 rem, unten nichts - und das ist die Rechnung, nicht das Gefuehl.**
   *
   * Oben steht die **Herkunftszeile im Polster**: 1 rem Abstand vom Bild, dann
   * ihre Zeile von rund 21 px. Bis der Claim anfaengt, sind davon schon 37 px
   * verbraucht - was als Abstand wirkt, ist der Rest.
   *
   * Unten steht **nichts im Polster**, und den Abstand nach unten traegt die
   * Buehne selbst (`.stage { margin-bottom: 2rem }`) und die naechste
   * Ueberschrift mit ihrem eigenen. Ein Polster hier waere der dritte
   * Abstand an derselben Kante - und drei Werte fuer eine Luecke sind drei
   * Stellen, an denen man sie sucht.
   */
  position: relative;
  padding: 7rem 0 0;
  clip-path: none;
  /* **Mittig, mit der Ortszeile darueber.** Auf der schwarzen Flaeche war der
     Block linksbuendig - er war die eine Kante unter einem randlosen Bild, und
     ein zentrierter Satz haette dort nichts gehabt, woran er sich ausrichtet.
     Auf Papier steht er unter einer Buehne, deren Gewicht links liegt: Die
     Mitte ist der Ausgleich, und die Ortszeile darueber ist die schmalste
     Zeile des Blocks - zentriert setzt sie den Block, linksbuendig haengt sie
     an ihm. */
  text-align: center;
}
/* **Die Herkunftszeile steht rechts unter dem Bild** - auf derselben
   Senkrechten wie das ⓘ darueber, und denselben Abstand von der Kante
   (`--credit-inset`, 1 rem).

   | | |
   |---|---|
   | **Sie ist eine Fussnote zum Bild, keine Zeile des Textes** | Im Fluss stand sie ueber dem Claim und las sich wie eine Dachzeile - eine Angabe daruebergesetzt, die etwas ueber die *Seite* zu sagen scheint. Am Bildrand sagt sie, was sie ist: woher dieses Foto kommt |
   | **Auf derselben Achse wie das ⓘ** | Das steht 1 rem von der rechten Bildkante; die Zeile steht 1 rem darunter und 1 rem von derselben Kante. Zwei Angaben zum selben Bild, eine Senkrechte - und ein Mass, nicht zwei |
   | **Sie nimmt den Fluss nicht mehr mit** | `position: absolute`. Deshalb kann der Block darueber und darunter dasselbe Mass tragen: Was mittig steht, ist Claim und Einleitung |
   | **Und sie bricht nicht um** | `white-space: nowrap`. Auf einem schmalen Fenster liefe sie sonst in zwei Zeilen und stiesse an den Claim; ein Eintragsname, der nicht danebenpasst, wird lieber am Rand abgeschnitten als in den Text geschoben |

   Die Reihe richtet sich ueber `justify-content` aus, nicht ueber
   `text-align`. */
.stage-start .stage-from {
  position: absolute; top: var(--credit-inset); right: var(--credit-inset);
  margin: 0; justify-content: flex-end; white-space: nowrap;
  max-width: calc(100% - 2 * var(--credit-inset)); overflow: hidden;
}
/* **Auf dem Telefon 2,25 rem** - der Claim steht hier nur, wenn die Startseite
   kein Buehnenbild hat; dann ist der Textblock die ganze Buehne. Mit 3 rem lief
   der Satz auf 390 px ueber sechs Zeilen. */
@media (max-width: 45.99rem) {
  .stage-start .stage-text .stage-claim { font-size: 2.25rem; }
}
.stage-text {
  background: var(--nav); color: var(--nav-ink);
  margin-top: -5vw;
  /* Mehr Luft ueber und unter dem Text: Der schwarze Grund braucht Raum, sonst
     liest er sich als Balken und nicht als Flaeche. Oben kommt die Hoehe der
     Schraege hinzu, sonst stuende die erste Zeile in der Spitze.
     (Stand 03.09.2026 noch einmal erhoeht - davor 3,4rem oben und 4rem unten.) */
  padding: calc(5vw + 5rem) 0 6rem;
  clip-path: polygon(0 5vw, 100% 0, 100% 100%, 0 100%);
}
.stage-inner { max-width: var(--rahmen-breite); margin: 0 auto; padding: 0 1.25rem; }
/**
 * **Der Text der Buehne steht als Block in der Mitte** - auf der Startseite und
 * ueberall, wo die Buehne nicht geteilt ist.
 *
 * Vorher lief er ueber die ganzen 1100 Pixel: Der Anspruch begann links, der
 * Satz darunter endete nach 700 - und die rechte Haelfte blieb leer, ohne dass
 * dort etwas gestanden haette. Als Spalte in der Mitte hat der Block eine
 * erkennbare Breite, und die Buehne wirkt gesetzt statt angeschnitten.
 *
 * Der Text darin bleibt **linksbuendig**: dieselbe Regel wie bei den
 * Bewertungen und beim langen Text - zentrierte Absaetze liest man schlechter,
 * weil jede Zeile woanders anfaengt.
 *
 * Die geteilte Buehne der Ortsseiten ist ausgenommen: Dort ist der Text schon
 * eine Haelfte, und eine Spalte in einer Haelfte waere eine Spalte in einer
 * Spalte.
 */
.stage:not(.stage-split) .stage-inner {
  max-width: 58rem;
  margin-inline: auto;
}
.stage-claim {
  /* Abstand nach der Ueberschrift, nicht davor: Darueber sitzt der Verweis mit
     seinem eigenen Abstand, darunter beginnt der Text - und der braucht Luft,
     damit die Ueberschrift eine Ueberschrift bleibt und keine erste Zeile. */
  margin: 0 0 1.8rem;
  /* **3 rem, fest.** Auf der Buehne steht ein Satz, der die H1 der Startseite
     ist - keine Zeile, die sich der Breite anpasst. Die geteilte Buehne behaelt
     ihre eigene, kleinere Rechnung weiter unten (`.stage-split .stage-claim`),
     und die Startseite auf dem Telefon ihre eigene gleich darunter. */
  font-size: 3rem; font-weight: 700;
  line-height: 1.15;
}
.stage-lead {
  /* **Keine eigene Breite mehr** (05.09.2026): Die 44 rem waren eine zweite,
     engere Schranke innerhalb der Spalte - der Text lief schmaler als die
     Ueberschrift darueber und sah aus wie eingerueckt. Begrenzt wird er jetzt
     nur noch von der Spalte selbst (`.stage-inner`, 58 rem). */
  margin: 0; font-size: 1.02rem; line-height: 1.55;
  color: color-mix(in srgb, var(--nav-ink) 88%, transparent);
}
/* **Auf der Startseite traegt der Lead mehr Gewicht** - am Schirm steht der
   Claim in der weissen Flaeche, und unter dem Bild ist die Einleitung der
   ganze Text. 1,5 rem, mit engerer Zeile, damit er ein Absatz bleibt. */
.stage-start .stage-lead { font-size: 1.5rem; line-height: 1.45; }

/* ---------------------------------------------------------------------------
   Die geteilte Buehne der Einstiegsseiten: links der Text, rechts das Bild.
   --------------------------------------------------------------------------- */

/* Zwei Spalten, das Bild quadratisch. Es bestimmt die Hoehe der Buehne - der
   Text richtet sich danach, nicht umgekehrt: Ein langer Text wuerde die Buehne
   sonst zu einem Absatz mit Foto machen. */
@media (min-width: 52rem) {
  /* Die Buehne ist so hoch wie das Fenster - das Bild rechts fuellt sie, der
     Text links steht mittig daneben. Die Hoehe ist damit eine Entscheidung und
     nicht das Ergebnis der Textlaenge. */
  .stage-split {
    /* **Halbe halbe** (so entschieden am 03.09.2026; davor eine schmalere
       Bildspalte). Gilt nur hier - auf dem Telefon bleiben Bild und Text
       gestapelt, dort gibt es keine zwei Haelften. */
    display: grid; grid-template-columns: 1fr 1fr; align-items: stretch;
    min-height: 100vh;
    min-height: 100dvh;
  }
  .stage-split .stage-text {
    /**
     * **Die Schraege sitzt an der rechten Kante** - die Trennung laeuft von
     * **unten links nach oben rechts**: oben reicht die schwarze Flaeche bis
     * zur Bildkante, unten endet sie 3,5vw davor. Dieselbe Richtung wie die
     * aufsteigende Kante auf der Startseite; ein Haus, eine Neigung.
     *
     * **`z-index` ist der Grund, warum man sie sieht.** Der Block schiebt sich
     * mit einem negativen Rand ueber das Bild - im Markup der Ortsseite steht
     * er aber **vor** dem Bild (der Text ist der Inhalt, das Bild die Zugabe,
     * und auf dem Telefon entscheidet die Reihenfolge). Ohne Stapelposition
     * malt der Browser das Bild danach darueber, und die Kante war
     * **senkrecht** - die Schraege gab es im Stylesheet und nicht auf dem
     * Schirm. Auf der Startseite fiel es nicht auf: Dort steht der Text hinter
     * dem Bild.
     */
    margin: 0 -3.5vw 0 0; padding: 0;
    display: flex; align-items: center;
    position: relative; z-index: 1;
    clip-path: polygon(0 0, 100% 0, calc(100% - 3.5vw) 100%, 0 100%);
  }
  .stage-split .stage-inner {
    max-width: none; width: 100%;
    /**
     * **Mittig in der eigenen Spalte** (03.09.2026).
     *
     * Vorher lief der linke Abstand ueber `max(1.25rem, calc(50vw - 550px))` -
     * er richtete den Text an der **Inhaltskante der Seite** aus, damit er auf
     * einer Linie mit dem steht, was darunter kommt. Die Absicht war richtig,
     * die Wirkung nicht: Bei 1400 Pixeln standen links 150 und rechts 94, und
     * damit klebte der Block an der rechten Kante seiner schwarzen Flaeche.
     *
     * Jetzt derselbe Wert auf beiden Seiten. Rechts kommt die halbe Schraege
     * dazu (`1.75vw`): Die Kante schneidet unten nach innen, und ohne diesen
     * Zuschlag sieht der Block optisch wieder nach rechts geschoben aus,
     * obwohl er rechnerisch mittig steht.
     *
     * Senkrecht mehr Raum als frueher (war 3,5rem) - der Text steht in einer
     * halben Bildschirmbreite, und eng gesetzt wirkt das gedraengt.
     */
    --stage-pad: clamp(1.5rem, 6vw, 5rem);
    padding: 5rem calc(var(--stage-pad) + 1.75vw) 5rem var(--stage-pad);
  }
  .stage-split .hero { height: 100%; }
  .stage-split .hero .photo, .stage-split .hero .photo img { height: 100%; }
  /* **Kein festes Seitenverhaeltnis mehr.** Quadratisch war richtig, solange die
     Buehne ihre Hoehe vom Text bekam; bei voller Fensterhoehe wuerde ein Quadrat
     so breit wie der Schirm hoch ist und den Text zusammendruecken. Der
     Ausschnitt fuellt jetzt die Spalte, und der Bildmittelpunkt (`focus`)
     entscheidet, was dabei stehen bleibt. */
  .stage-split .hero .photo img { aspect-ratio: auto; object-fit: cover; }
  .stage-split .hero-from { right: 0; }
}
/* Auf dem Telefon untereinander - **Bild oben, Text darunter**. Im Markup steht
   der Text zuerst (er ist der Inhalt, das Bild die Zugabe); die Reihenfolge auf
   dem Schirm dreht `order`, nicht das Markup.

   Die Schraege sitzt hier **unter** dem Text und nicht zwischen Bild und Text:
   Zwischen zwei gestapelten Bloecken waere sie ein Knick, unter dem Block ist
   sie der Abschluss - dieselbe Bewegung wie beim Fuss. */
@media (max-width: 51.99rem) {
  .stage-split { display: flex; flex-direction: column; }
  .stage-split .hero { order: 1; }
  .stage-split .stage-text { order: 2; }
  /* Auf dem Telefon ebenfalls die volle Hoehe - der Text beginnt damit unter dem
     ersten Bildschirm. Das ist gewollt: Ein Eingang zeigt zuerst den Ort. */
  .stage-split .hero .photo img { aspect-ratio: auto; height: 100vh; height: 100dvh; }
  .stage-split .stage-text {
    clip-path: polygon(0 0, 100% 0, 100% calc(100% - 6vw), 0 100%);
    padding-bottom: 6vw;
  }
  /* Gestapelt liegt die schwarze Flaeche mit ihrem negativen Rand ueber dem
     unteren Bildrand - dieselben 5vw wie auf der Startseite. Am Schirm gibt es
     das nicht: Dort steht sie **neben** dem Bild, und die Schraege laeuft
     senkrecht an der rechten Kante des Textes. */
  .stage-split { --stage-overlap: 5vw; }
  .stage-split .stage-inner { padding: 3rem 1.25rem 3.6rem; }
}
.stage-split .stage-text { background: var(--nav); color: var(--nav-ink); }

/* Eine Buehne ohne Kopfbild: nur der schwarze Block, ueber die volle Breite,
   mit der Schraege unten. Kein Bild ist besser als ein fremdes - und besser als
   eine leere Haelfte. */
.stage-plain .stage-text {
  background: var(--nav); color: var(--nav-ink);
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - 5vw), 0 100%);
  padding-bottom: 5vw;
}
.stage-plain .stage-inner {
  max-width: var(--rahmen-breite); margin: 0 auto;
  padding: calc(var(--navheight, 3.7rem) + 3.5rem) 1.25rem 4rem;
}
/* **Ueberschriften auf der Buehne erben ihre Farbe.** Die globale Regel setzt
   sie auf `--strong` - und das ist auf schwarzem Grund schwarz auf schwarz. Ein
   Titel, den man nicht sieht, war genau das. */
.stage-text h1, .stage-text h2, .stage-text p { color: inherit; }

/* Die Ueberschrift der Buehne ist die H1 der Seite - sie braucht die Groesse
   einer Ueberschrift, nicht die eines Claims. */
.stage-split .stage-claim { font-size: clamp(1.6rem, 3.6vw, 2.4rem); }

/* Das Wetter - **klein, direkt unter dem Ortspin.**
   Keine Karte mit Rahmen: Es ist eine Beigabe zur Ortszeile, kein Abschnitt.
   Deshalb dieselbe Zeilenform wie Pin und Datum, nur eine Spur leiser. */
/* **Die Zeile ist so hoch, bevor sie etwas sagt, wie danach.**

   Vorher stand sie `hidden` im Dokument und klappte auf, sobald der
   Wetterdienst geantwortet hatte - alles darunter rutschte. `min-height` haelt
   den Platz von Anfang an frei; ob die Zeile leer ist, einen Balken zeigt oder
   die Temperatur, aendert an der Hoehe nichts.

   Der Wert ist die Zeilenhoehe des Textes darin (1rem * 1.55), nicht getippt
   geraten - er ergibt sich aus derselben Rechnung wie die Zeile selbst. */
.weather-line { margin: .1rem 0 .25rem; color: var(--soft); min-height: 1.55rem; }

/* Der Balken an der Stelle, an der gleich die Zahl steht. Breite wie
   „12° · bewoelkt" samt Zeichen (gemessen 101 bis 107 px): Die Zeile steht
   mittig, und ein breiterer Balken liesse sie beim Tausch zur Seite ruecken. */
/* **Leicht gerundet - die eine Ausnahme von `border-radius: 0`.**

   Kanten sind Marke, und das gilt fuer alles, was zur Seite gehoert. Dieser
   Balken gehoert nicht dazu: Er ist kein Bauteil, sondern die Andeutung eines
   Bauteils, das gleich kommt - sichtbar nur fuer den Moment des Wartens. Die
   Rundung sagt genau das, naemlich "hier steht noch nichts Festes". */
.weather-skeleton {
  display: inline-block; width: 6.5rem; height: .8rem; border-radius: .25rem;
  background: var(--line);
  animation: weather-pulse 1.4s ease-in-out infinite;
}
@keyframes weather-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
/* Wer Bewegung abbestellt hat, bekommt einen ruhigen Balken - keinen Puls. */
@media (prefers-reduced-motion: reduce) {
  .weather-skeleton { animation: none; }
}
.weather-line .weather-icon { width: 1rem; height: 1rem; flex: none; color: var(--soft); }
.weather-line span { font-variant-numeric: tabular-nums; }

/* Angaben als Paare: **links der Begriff, rechts der Wert.**
   Adresse, Kontakt und Merkmale sind dieselbe Art von Angabe und stehen deshalb
   in derselben Form - vorher war eines eine Aufzaehlung mit Punkten, das andere
   eine Liste aus Paaren, direkt untereinander.

   Zwei Spalten im Raster statt schwebender Definitionsliste: Der Begriff hat
   eine feste Breite, die Werte stehen auf einer Kante. Eine Linie je Zeile,
   keine Kaesten. */
.pairs {
  display: grid; grid-template-columns: minmax(7rem, 12rem) 1fr;
  gap: 0; margin: .4rem 0 1.6rem; max-width: 44rem;
}
.pairs dt, .pairs dd {
  margin: 0; padding: .7rem 0; border-top: 1px solid var(--line);
  font-size: .95rem; line-height: 1.45;
}
.pairs dt { color: var(--soft); padding-right: 1rem; }
/**
 * **Eine lange Adresse darf brechen** - `overflow-wrap: anywhere`, und das
 * `min-width: 0` dazu.
 *
 * Ein Rasterfeld ist von sich aus nie schmaler als sein laengstes
 * unteilbares Wort, und „enbw.com/unternehmen/themen/wasserkraft/…" ist ein
 * solches Wort: Es machte die Liste **508 px** breit und damit die ganze
 * Eintragsseite auf einem Telefon von 390 px waagerecht rollbar. Der Browser
 * zoomte daraufhin heraus (`innerWidth` 613 statt 390) - die Seite sah
 * „kleiner" aus, und niemand haette den Grund bei einer Telefonnummer
 * gesucht. `anywhere` statt `break-word`, weil nur das auch die **kleinste**
 * Breite des Feldes senkt.
 */
.pairs dd { color: var(--ink); min-width: 0; overflow-wrap: anywhere; }
.pairs dd a { color: var(--ink); }
.pairs dd a:hover, .pairs dd a:focus-visible { color: var(--accent); }
/* Auf dem Telefon untereinander: Zwei Spalten auf 320 Pixeln lassen dem Wert
   keinen Platz, und "Öffnungszeiten" bricht dreimal um. */
@media (max-width: 32rem) {
  .pairs { grid-template-columns: 1fr; }
  .pairs dt { padding-bottom: 0; border-top: 1px solid var(--line); }
  .pairs dd { padding-top: .15rem; border-top: 0; }
}

/* ---------------------------------------------------------------------------
   **Die Kanäle in der Kontaktzeile** (07.09.2026)

   Zeichen und Wort, und beide gehören demselben Griff: Wer auf das Logo
   zielt, meint den Kanal, und wer auf das Wort zielt, auch.

   **`currentColor`, keine Markenfarben.** Drei Gründe, jeder allein tragend:
   Farbe ist im Haus an die vier Bereiche gebunden – fünf fremde Markenfarben in
   einer Zelle sind fünf Aussagen, die nichts über diesen Ort sagen. Instagram
   ist ein Verlauf und kein Farbwert; ein nachgebauter Verlauf wäre ein falsches
   Logo. Und im Dunkelmodus müsste jede Farbe einzeln gegen `--paper` geprüft
   werden. So ist es eine Regel statt fünf Sonderfällen, und beide Modi tragen.

   Das Zeichen misst `1em` und nicht `rem`: Es steht in einer Textzeile und soll
   mit ihr wachsen. Der Innenabstand bringt die Zeile über die 44 px, die ein
   Daumen braucht – auf dem Telefon ist das der Unterschied zwischen getroffen
   und daneben.
   --------------------------------------------------------------------------- */
.entry-social {
  list-style: none; padding: 0;
  display: flex; flex-wrap: wrap; column-gap: 1.1rem; row-gap: .1rem;
  /**
   * **Der Innenabstand der Verweise wird oben und unten zurückgenommen**
   * (07.09.2026). Er ist die Trefffläche für den Daumen – und er schob die
   * erste Zeile um .35rem nach unten, sodass „Instagram" tiefer stand als
   * „Social Media" daneben. In einer Tabelle aus Begriff und Wert ist die
   * gemeinsame Grundlinie das, was die beiden überhaupt als Paar lesbar macht;
   * jede andere Zeile hier hat sie.
   *
   * Negativer Rand statt weniger Abstand: Die Fläche bleibt, nur ihr Platz
   * wird nicht zweimal gerechnet – `dd` bringt seine `.7rem` schon mit.
   */
  margin: -.35rem 0;
}
.entry-social a {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .35rem 0; text-decoration: none;
}
/**
 * **Ohne Zeigegerät 44 px** - dieselbe Rechnung wie an der Zeilenlinie im
 * Editor: 22 px Zeile plus zweimal .7rem sind 44,4. Am Schirm bleibt es bei
 * .35rem, dort trifft eine Maus genau. Und die zwei Zeilen des Umbruchs
 * bekommen Luft dazwischen - 1,6 px sind kein Abstand zwischen zwei Zielen.
 */
@media (pointer: coarse) {
  .entry-social { margin: -.7rem 0; row-gap: .35rem; }
  .entry-social a { padding: .7rem 0; }
}
.entry-social a span { text-decoration: underline; text-underline-offset: .18em; }
.social-glyph {
  flex: none; width: 1em; height: 1em; fill: currentColor;
  vertical-align: -.13em;
}

/* ---------------------------------------------------------------------------
   Der Kennungsblock einer Eintragsseite: Rubrik, Name, Ort - mittig.
   --------------------------------------------------------------------------- */

/* Mittig und mit Luft: Diese vier Zeilen sind der Kopf, den man in einem Blick
   liest. Begrenzt, damit ein langer Name nicht ueber die ganze Breite laeuft -
   zentrierte Zeilen ueber 1100 Pixel findet das Auge nicht wieder. */
.item-ident {
  text-align: center; max-width: 46rem; margin: 0 auto 2rem;
  display: grid; justify-items: center; gap: .1rem;
}
.item-ident h1 {
  /* Groesser als zuvor (war 1,8rem): Der Name ist die Ueberschrift der Seite,
     und mittig gesetzt braucht er Gewicht, sonst schwimmt er. */
  font-size: clamp(1.9rem, 4vw, 2.6rem); line-height: 1.12; margin: .3rem 0 .5rem;
}
.item-ident .place { margin: .1rem 0; justify-content: center; }

/**
 * **Der Punkt an der Tuer: gruen offen, rot zu.**
 *
 * Farbe **und** Wort. Die Farbe ist die schnelle Auskunft, das Wort die
 * verlaessliche: Rund acht Prozent der Maenner sehen Rot und Gruen nicht
 * auseinander, und eine Auskunft, die nur an einer Farbe haengt, ist fuer sie
 * keine. Deshalb steht "Ist geöffnet" fett daneben und der Punkt ist
 * `aria-hidden` - ein Vorleseprogramm liest den Satz, nicht die Farbe.
 *
 * Die beiden Toene kommen **nicht** aus der Rubrikpalette: Sie bedeuten hier
 * nichts ueber die Art des Ortes, sondern ueber einen Zustand. Ein Gruen aus
 * "Erleben" an dieser Stelle waere eine falsche Verbindung.
 */
/**
 * **Dieselbe Groesse wie die Zeilen darueber.**
 *
 * Unter dem Titel stehen drei Angaben in derselben Rolle: Ort, Zustand der
 * Tuer, Wetter. Sie hatten drei Groessen (13.6, 15.2 und 13.12 Pixel) - jede
 * fuer sich begruendbar, zusammen eine Treppe. Die Zeilen erben jetzt von
 * `.place`; hervorgehoben wird der Zustand durch den Punkt und das fette Wort,
 * nicht durch die Schriftgroesse.
 */
.open-dot {
  width: .6rem; height: .6rem; flex: none; border-radius: 50%;
  background: #b3261e;
}
.open-dot.is-open { background: #1e7b34; }
/* **The dot stands in the sentence, not beside it.** As a flex item it stayed
   at the left edge of the column when the text broke onto a second line - the
   text centred itself, the dot did not. Inline it travels with the first word. */
.open-line .where { display: inline; }
.open-line .open-dot { display: inline-block; vertical-align: .05em; margin-right: .1rem; }
.open-line strong { color: var(--strong); font-weight: 700; }

/* Die Woche im Angabenblock: Tag links, Zeiten rechts - ein Raster, damit die
   Uhrzeiten untereinander stehen und man die Ausnahme im Vorbeisehen findet. */
.hours-week {
  display: grid; grid-template-columns: 4.6rem 1fr; gap: .15rem .8rem;
  font-variant-numeric: tabular-nums;
}
.hours-day { display: contents; }
.hours-day > span:first-child { color: var(--soft); }
.hours-note {
  display: block; margin-top: .5rem; color: var(--soft); font-size: .85rem;
  line-height: 1.45;
}
.item-ident .facts { justify-content: center; }

/* **The head line: where am I, as a row of pills** (`BFP.rubrikLine`) - a
   breadcrumb above the name of an entry, a story and an event. Far left
   "Startseite" in black, then the section filled in its colour, then the next
   level: an entry's kinds in the softened tint of the same colour, the date
   of a story or an event in grey. Small monospace pills side by side - the
   classification, not the message; the form of the place in a calendar row.

   The colour comes in as `--rf` / `--rf-voll` (gold reads its ink for the
   filled pill, white on light gold would be 2.55 : 1). The tint keeps the
   strong ink: a dark colour on its own tint in dark mode would vanish. */
.rubrik {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center;
  gap: .4rem; margin: 0 0 .6rem;
}
.rubrik-pille {
  display: inline-flex; align-items: center; min-height: 1.4rem;
  padding: .25rem .75rem; border-radius: 999px; background: var(--shade);
  font-family: var(--mono); font-size: .68rem; line-height: 1.5; color: var(--soft);
  white-space: nowrap; text-decoration: none;
}
.rubrik-pille-start { background: var(--strong); color: var(--paper); }
.rubrik-pille-bereich { background: var(--rf-voll); color: var(--auf-bild-ink); }
/* Events have no category colour: their section pill is grey like the date,
   but in the strong ink - it is a way somewhere, the date is not. */
.rubrik-pille-bereich[data-ton="strong"] { background: var(--shade); color: var(--strong); }
.rubrik-pille-ebene { background: color-mix(in srgb, var(--rf) 18%, var(--paper)); color: var(--strong); }
a.rubrik-pille:hover { text-decoration: underline; text-underline-offset: .2em; }
a.rubrik-pille:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* **The date block of a recurring event whose next date is open** - where the
   date would stand: under the head, before the pictures. Three sentences in
   the reading column, the calendar sign in front of the first; the way to the
   organiser is a plain link, because that is where the date appears first. */
.termin-offen { max-width: var(--text, 52rem); margin: 0 auto 1.6rem; padding: 0 1.25rem; }
.termin-offen p { margin: 0 0 .35rem; }
.termin-offen .termin-offen-satz { display: flex; align-items: flex-start; gap: .5rem; font-weight: 700; }
.termin-offen .cal-icon { width: 1.3rem; height: 1.3rem; flex: none; stroke: var(--strong); margin-top: .1rem; }
.termin-offen .termin-offen-zuletzt { color: var(--soft); }

/* Fast die ganze Hoehe: Eine Karte, die man einstellen kann, muss auch etwas
   zeigen koennen - ein Streifen von 300 Pixeln beantwortet keine Frage. */
.tourmap-big { height: clamp(24rem, 78vh, 60rem); }

/* **Der lange Text** - nach dem Bild, in der Lesespalte. Ruhiger Satz, etwas
   mehr Zeilenabstand als der Rest: Er ist der einzige Ort auf dieser Seite, an
   dem jemand wirklich liest. */
/* Zentriert wie der Kopf der Seite: Titel, Ort und Kurzbeschreibung stehen
   mittig, und ein linksbuendiger Block darunter waere ein Bruch in derselben
   Spalte. */
/* **Linksbuendig, nicht zentriert** (03.09.2026).

   Zentriert war der lange Text, solange er ein Absatz war. Er ist aber der
   Fliesstext der Seite - Geschichte, Bauweise, Ablauf - und ein zentrierter
   Fliesstext hat an jeder Zeile einen anderen Anfang. Das Auge sucht beim
   Zeilenwechsel den linken Rand; gibt es keinen, liest es langsamer.

   Der Kasten bleibt mittig (`margin: auto`), nur sein Inhalt nicht. */
.item-text { margin: 1.8rem auto 2.4rem; text-align: left; }
/**
 * **Der lange Text endet nach 26 Zeilen im Verlauf - 44em.**
 *
 * **Was hier gemessen wird, ist Wischstrecke, nicht Textmenge.** Die Kuerzung
 * gibt es, damit Oeffnungszeiten, Telefon, Karte und Fragen nicht hinter einer
 * Textwand liegen - und dieser Weg zaehlt in Pixeln. Deshalb eine **Hoehe**
 * und keine Zeichenzahl: Fuenf Saetze sind mal zwei Zeilen und mal zwoelf, und
 * im Skript zaehlen laesst sich ein Satz ohnehin nicht („z. B.", „ca. 3 km").
 *
 * **Und deshalb auch kein zweiter Wert fuers Telefon.** Dass hinter derselben
 * Hoehe am Schirm doppelt so viele Zeichen stehen (79 gegen 36 je Zeile,
 * gemessen), ist eine Eigenschaft des Geraets und kein Fehler: Auf dem Telefon
 * ist eine lange Strecke **schlimmer**, nicht milder - dort steht der Gast
 * draussen und will die Nummer. Eine Grenze, die dort mehr durchliesse, drehte
 * den Zweck um.
 *
 * **44em sind gemessen, nicht gefuehlt** (Stand 17.09.2026, 47 Seiten mit
 * langem Text): Der Bestand hat zwei Gipfel - ein Viertel der Texte ist **ein
 * Satz** (120 Zeichen), die Mitte liegt bei 1200 bis 1700, und ab rund 2500
 * faengt der Artikel an. Dazwischen liegt die Kante. 26 Zeilen sind am Schirm
 * rund 2050 Zeichen und treffen damit **zehn** Seiten - die Gruppe ab 2500 -,
 * waehrend die ganze Mitte stehen bleibt. Bei den vorherigen zehn Zeilen waren
 * es am Schirm 800 Zeichen und auf dem Telefon **368**, also zwei Saetze.
 *
 * Der Verlauf bleibt bei 7em: Auf 272 px waren das 41 Prozent des sichtbaren
 * Textes, auf 704 px sind es 16.
 *
 * **Der Verlauf laeuft nach `--paper`, nicht nach Weiss.** Gewuenscht war „ein
 * Verlauf in weiss" - und genau so waere er im Dunkelmodus ein heller Streifen
 * quer durch den Text. Die Farbe ist der Grund der Seite, und der hat einen
 * Namen (Hell und Dunkel immer, siehe Palette oben).
 *
 * Der Text bleibt dabei **vollstaendig im Dokument**: `overflow: hidden`, kein
 * Beschneiden im Skript. Was eine Maschine liest, ist der ganze Text - dafuer
 * gibt es ihn. Eine Suchmaschine sieht also keinen gekuerzten Text, sondern
 * denselben wie ein Mensch, der aufgeklappt hat.
 */
.item-text.is-kurz {
  position: relative; max-height: 44em; overflow: hidden;
}
.item-text.is-kurz::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 7em;
  background: linear-gradient(to bottom, transparent, var(--paper));
  pointer-events: none;
}
/* Der Knopf steht unter dem Verlauf, nicht darin: Er gehoert zur Seite und
   nicht zum Text. Ohne Kuerzung ist die Zeile `hidden` - siehe `textKuerzen`. */
.item-mehr { margin: -1.6rem auto 2.4rem; max-width: var(--text); text-align: left; }
.item-text p { margin: 0 0 1rem; font-size: 1.02rem; line-height: 1.65; }
.item-text p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------------------
   Bewertungen - unter den Fragen.
   ---------------------------------------------------------------------------

   Die Reihenfolge ist die Aussage: erst das Pruefbare, dann das Empfundene.
   Der Hinweis auf das Memberprofil steht **ueber** dem Knopf und gedaempft - er
   ist die Bedingung, nicht die Werbung, und eine Bedingung gehoert vor die
   Handlung. */
/* **Alles darunter steht links - der Block selbst steht mittig.**
   Die Bewertungen sind Text: Absender, Datum, Satz. Text liest man
   linksbuendig, und der Knopf gehoert zu diesem Text - `.actions` steht seit
   dem 03.09.2026 ohnehin links, hier braucht es also keine Ausnahme.
   Der Block ist dabei nur so breit wie die Lesespalte und liegt in der Mitte
   wie alles andere auf der Eintragsseite; ueber die volle Rahmenbreite gezogen
   waere die Trennlinie ueber jeder Bewertung laenger als der Satz darunter. */
.ratings { text-align: left; max-width: var(--text); margin: 0 auto 2.4rem; }
.ratings-list { list-style: none; margin: 0 0 1.4rem; padding: 0; text-align: left; }
/* **"Meine Bewertungen"** - the same line as at the entry, the state pill at
   the end of its head. The pill stands in regular weight here: it is a quiet
   note beside the name, not a heading, and the bold one read as a second name.
   A waiting change is a second line below with its own bubble. */
.stimme-meine > div { flex: 1; min-width: 0; }
.stimme-meine-zeile { margin-top: .7rem; }
.stimme-meine .stimme-kopf { flex-wrap: wrap; }
.stimme-zusatz { margin-left: auto; }
.stimme-meine .konto-status { font-weight: 400; }
.stimme-meine .stimme-blase { margin: .75rem 0 0; }
.stimme-meine .konto-notiz { margin-top: .6rem; }
.stimme-vorschau-name { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .8rem; margin: 1.4rem 0 0; }
.stimme-vorschau-name > span { font-size: .86rem; font-weight: 600; }
#vorschau-regeln { display: block; margin: 1rem 0 1.2rem; }
/* **One voice: portrait, name and stars, then the sentence as a speech bubble.**
   The bubble replaces the rule between two ratings - its own ground separates
   them, and a line above each would be a second edge for the same thing. The
   tail sits under the centre of the portrait: the words belong to that person.
   The portrait is round like every portrait of the house (`.nav-konto-bild`,
   `.avatar-schau`); without a picture it carries the initials, the same
   placeholder as the profile page. The head sits a little in from the left
   edge (`--stimme-einzug`), and the tail moves with it - it stays under the
   centre of the portrait. **The bubble has rounded corners**, the documented
   exception to `border-radius: 0`: a speech bubble is a form, not a box of the
   layout, and square it read as a grey panel with a notch. */
.ratings-list li { padding: .7rem 0; }
.ratings-list p { margin: 0; }
.ratings-list, .stimme-meine { --stimme-bild: 2.5rem; --stimme-einzug: .75rem; }
.stimme-kopf { display: flex; align-items: center; gap: .75rem; padding-left: var(--stimme-einzug); }
.stimme-bild {
  width: var(--stimme-bild); height: var(--stimme-bild); flex: none;
  border-radius: 50%; object-fit: cover; background: var(--shade); display: block;
}
.stimme-initialen {
  display: grid; place-items: center;
  font-size: .9rem; font-weight: 400; letter-spacing: .02em;
  /* Black with white letters, like every black square of the house - and
     like them it turns light in the dark (`--nav`), where a black circle
     would vanish into the paper. */
  background: var(--nav); color: var(--nav-ink);
}
.stimme-wer { min-width: 0; display: grid; gap: .1rem; }
.stimme-wer .stars { margin-bottom: 0; }
.ratings-by { color: var(--soft); font-size: .85rem; }
.stimme-blase {
  position: relative; padding: .8rem 1rem;
  background: var(--shade); border-radius: .75rem;
}
.ratings-list .stimme-blase { margin: .75rem 0 0; }
.stimme-blase::before {
  content: ""; position: absolute; top: -.5rem;
  left: calc(var(--stimme-einzug, .75rem) + var(--stimme-bild, 2.5rem) / 2 - .5rem);
  width: 1rem; height: .5rem; background: inherit;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
/* **Every second voice from the right** - portrait, name and stars mirror to
   the right edge, and the tail moves with the portrait; it reads as a
   conversation and not as a form. Only the head mirrors: the sentence in the
   bubble stays left-aligned, because a ragged left edge is harder to read.
   The order in the list stays newest first; the side is only form. */
.ratings-list li:nth-child(even) .stimme-kopf {
  flex-direction: row-reverse; padding-left: 0; padding-right: var(--stimme-einzug);
}
.ratings-list li:nth-child(even) .stimme-wer { justify-items: end; text-align: right; }
.ratings-list li:nth-child(even) .stimme-blase::before {
  left: auto; right: calc(var(--stimme-einzug, .75rem) + var(--stimme-bild, 2.5rem) / 2 - .5rem);
}
/* Der Sternestreifen einer einzelnen Stimme.

   **Die leeren Sterne bleiben stehen** - vier gefuellte allein sagen nicht, ob
   von fuenf oder von zehn. Gefuellt heisst `fill`, leer heisst nur Kontur: Die
   Zeichnung im Sprite ist strichbasiert, also traegt `fill: currentColor` den
   Unterschied und nicht zwei Zeichen.

   Der Streifen fuehrt seine Aussage als `aria-label` **und** `title` mit; die
   Farbe ist die Textfarbe und nicht Gold - eine eigene Farbe fuer Sterne waere
   eine sechste Erkennungsfarbe neben den fuenf der Rubriken. */
.stars { display: inline-flex; gap: .1rem; margin-bottom: .25rem; }
.stars .star { display: inline-flex; color: var(--line); }
.stars .star-voll { color: var(--strong); }
.stars .star svg { width: 18px; height: 18px; }
.stars .star-voll svg { fill: currentColor; }
.ratings .actions { margin: 0; }
/* Der Hinweis steht als Satz in der Zeile darueber statt als eigener Absatz
   unter dem Knopf - eine Voraussetzung gehoert vor die Handlung, nicht
   dahinter. Damit traegt `.count` den Text, und `.ratings-note` ist entfallen.

   **Ueber die ganze Breite**, also so weit wie `.ratings` selbst und damit so
   weit wie die Bewertungen, die spaeter darunter stehen. Vorher waren es
   34rem: eine eigene Lesebreite fuer einen Satz, der an derselben linken Kante
   beginnt wie die Liste - und rechts vorher aufhoerte. Zwei Breiten
   uebereinander lesen sich wie zwei Spalten, die nicht zusammengehoeren. */
.ratings .count { line-height: 1.5; margin: 0 0 1rem; }

/* ---------------------------------------------------------------------------
   Die Galerie: drei Kacheln, egal wie viele Bilder es sind.
   ---------------------------------------------------------------------------

   Eins gross links, zwei klein rechts - und auf der letzten steht „alle Bilder
   anzeigen". Die Anordnung sagt damit zwei Dinge auf einmal: welches Bild das
   wichtigste ist, und dass es mehr gibt. Ein Raster aus allen Bildern koennte
   nur das Zweite, und es schiebt den Text nach unten.

   Drei Spalten, zwei Zeilen: Die grosse Kachel nimmt zwei Spalten und beide
   Zeilen ein, die kleinen sitzen in der dritten. Ein Bild bleibt ein Bild -
   ohne Rahmen, ohne Rand, ohne Schatten. */
/* **Das Raster hat ein festes Verhaeltnis, keine gewachsenen Zeilen.**
   9:4 fuer die ganze Flaeche ist nicht willkuerlich: Bei zwei Drittel Breite
   fuer die grosse Kachel und zwei Zeilen rechts kommt genau dann bei allen drei
   Kacheln 3:2 heraus - dasselbe Verhaeltnis, das jedes Bild im Guide hat.

   Der erste Versuch liess die Zeilen wachsen und gab den Bildern `height: 100%`.
   Das ist ein Ring: Die Zeile richtet sich nach dem Bild, das Bild nach der
   Zeile. Der Browser loest ihn irgendwie - hier mit 297 und 120 Pixeln fuer
   zwei Kacheln, die gleich gross sein sollten, und einer dritten ohne Breite.
   Mit einem gesetzten Verhaeltnis steht die Hoehe vorher fest, und `1fr 1fr`
   teilt sie genau. */
/* ---------------------------------------------------------------------------
   Die Tipp-Box - ein Satz vom Absender, ueber Adresse und Kontakt.
   ---------------------------------------------------------------------------

   **Keine Kategoriefarbe.** Die fuenf Farben gehoeren ihren Rubriken und sagen
   dort, wo man ist; hier waere eine davon eine falsche Aussage. Der Kasten
   nimmt deshalb `--strong` fuer den Balken und einen sehr leichten Grund aus
   demselben Token - er hebt sich ab, ohne eine zweite Farbsprache anzufangen.

   Ecken bleiben eckig (Styleguide), und die Lesebreite ist dieselbe wie beim
   Text: Ein Tipp ist ein Satz und keine Tafel. */
.tip {
  max-width: var(--text); margin: 0 auto 1.6rem;
  border-left: 3px solid var(--strong);
  background: color-mix(in srgb, var(--strong) 5%, transparent);
  padding: .9rem 1.1rem; text-align: left;
}
.tip p { margin: 0; }
/* Die Zeile sagt, **wer** spricht - bei einer Antwort steht dort eine Quelle,
   hier der Absender. Deshalb schmaler und in der weichen Farbe, wie eine
   Herkunftsangabe, nicht wie eine Ueberschrift. */
.tip-head {
  display: flex; align-items: center; gap: .4rem;
  font-size: .82rem; letter-spacing: .02em; text-transform: uppercase;
  color: var(--soft); margin-bottom: .35rem;
}
.tip-head .glyph { color: var(--strong); }

/* ---------------------------------------------------------------------------
   MEIN EINTRAG - die Seite eines beanspruchten Betriebs (05.09.2026)
   ---------------------------------------------------------------------------

   **Die Pille sagt die Stufe.** Sie steht neben dem Namen - in der Liste und im
   Kopf der Seite - und ist bewusst klein und ruhig: Sie ist eine Angabe, kein
   Abzeichen. PLUS bekommt die starke Farbe, weil genau das der Unterschied ist,
   den man sehen soll; „Member" bleibt in der Linie.

   Die abgerundete Ecke ist eine der dokumentierten Ausnahmen (wie die
   Hilfe-Pille): Eine Pille mit rechten Ecken ist ein Kasten. */
/**
 * **Eine Pille braucht eine Flaeche, kein Haarband.**
 *
 * Sie stand als Umriss in `--line` da - auf weissem Grund ein Ring von einem
 * Pixel um drei kleine Woerter, und auf der grauen Aufstellerkarte war er
 * gar nicht mehr zu sehen. Gefuellt ist sie das, was sie sein soll: eine
 * Marke. Genommen ist `--shade`, die leise Fuellung des Hauses - und auf
 * grauem Grund tauscht sie mit ihm (siehe `.qr-karte .plan-pille`), damit der
 * Helligkeitsschritt bleibt.
 */
.plan-pille {
  display: inline-block; vertical-align: 2px;
  padding: .25rem .75rem; margin-left: .4rem;
  border: 0; border-radius: 999px; background: var(--shade);
  /* Monospace und normal geschnitten: Eine Pille ist eine **Systemangabe** -
     „PRO", „stillgelegt" -, kein Wort im Satz. Dieselbe Schrift wie an jeder
     anderen Angabe, die die Software macht und kein Mensch schreibt. */
  font-family: var(--mono); font-size: .68rem; font-weight: 400;
  letter-spacing: .04em;
  text-transform: uppercase; color: var(--soft); white-space: nowrap;
}
.qr-karte .plan-pille { background: var(--card-ground); }
.plan-pille[data-plan="plus"] {
  border-color: var(--strong); color: var(--strong);
  background: color-mix(in srgb, var(--strong) 8%, transparent);
}
/* PRO ist die hoechste Stufe - gefuellt statt umrandet: Sie soll sich von PLUS
   auf einen Blick unterscheiden, ohne eine zweite Farbe einzufuehren. */
/* **Eine Zeile, die etwas tut, sagt das auch** - Zeiger und ein heller Grund
   beim Zeigen. Der Fokusrahmen liegt innen (`inset`): Ein Umriss um eine
   Tabellenzeile schneidet der Browser an den Zellgrenzen ab. */
.zeile-klick { cursor: pointer; }
.zeile-klick:hover { background: var(--shade); }
.zeile-klick:focus-visible {
  outline: none; box-shadow: inset 0 0 0 2px var(--strong);
}

.plan-pille[data-plan="pro"] {
  border-color: var(--strong); background: var(--strong); color: var(--paper);
}
/* **A service bought once is outlined, not filled** - the same pill, so it
   belongs to the page, but a line instead of a surface: filled pills are the
   tiers (Member, PLUS, PRO), and a Zusatzleistung is none. The padding gives
   back the pixel the line takes, so it stands as high as a tier pill. */
.plan-pille[data-plan="einmalig"] {
  border: 1px solid var(--strong); background: transparent; color: var(--strong);
}
.abo-plan-kopf .plan-pille[data-plan="einmalig"] { padding: calc(.25rem - 1px) calc(.7rem - 1px); }
/**
 * **Die Stufenpille steht mittig in der Ueberschrift** (05.09.2026).
 *
 * `vertical-align: 2px` ist auf Fliesstext eingestellt - neben einem Namen in
 * Fettschrift in einer Tabellenzeile sitzt die Pille damit richtig. In dieser
 * Ueberschrift ist die Schrift bis zu 2 rem hoch, und ein Anstupser von zwei
 * Pixeln ueber der Grundlinie laesst eine 0,7-rem-Pille darunter haengen: Sie
 * steht auf dem Fuss der Buchstaben statt in ihrer Mitte.
 *
 * Deshalb hier keine Verschiebung, sondern eine **Zeile**: `flex` mit
 * `center`, und die Mitte findet der Browser selbst - auch dann noch, wenn
 * `clamp()` die Ueberschrift auf einem schmalen Schirm kleiner setzt. Der
 * Abstand kommt aus dem `gap`, der eigene Rand der Pille faellt weg.
 */
/* One head for both areas of a house under "Mein Betrieb" ("Mein Eintrag",
   the digital guest folder) - one class, so switching between them moves
   nothing (`betriebKopf` in `profil.js`). */
.betrieb-kopf h1 {
  margin-bottom: .2rem;
  display: flex; align-items: center; flex-wrap: wrap; gap: .5rem;
}
.betrieb-kopf h1 .plan-pille { vertical-align: 0; margin-left: 0; }
/**
 * **Die Teile der Gaestemappe stehen auf einer Tafel** - wie jede Flaeche des
 * Backends, auf der gearbeitet wird. Sie sind ein eigener Bereich und fallen
 * damit nicht unter `tafelnBauen` (`data-ohne-tafel`), also traegt die Tafel
 * hier der Behaelter selbst.
 *
 * **Die Vorschau nicht:** Sie hat schon einen Rahmen - den Telefonrahmen -,
 * und ein Telefon auf einem Blatt Papier waere ein Kasten im Kasten.
 */
/* **Dieselbe Breite wie eine Tafel im Editor** (46 rem): Was hier steht, ist
   ein Formular mit Feldern und Zeilen - dieselbe Sorte Arbeit, also dieselbe
   Lesespalte. Sie gilt auch fuer die Vorschau, damit der Telefonrahmen an
   derselben Kante beginnt wie die Tafeln daneben. */
#mappe-tafel { max-width: 46rem; }
#mappe-tafel:not(:has(.mp-vorschau)) {
  background: var(--card-ground);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
  padding: 1.4rem;
}
#mappe-tafel > :first-child { margin-top: 0; }
#mappe-tafel > :last-child { margin-bottom: 0; }

.mein-hinweis { max-width: var(--text); margin: 0 0 1.4rem; color: var(--soft); }
.mein-hinweis h2 { color: var(--ink); margin: 0 0 .4rem; font-size: 1.1rem; }
/**
 * **Die Knopfzeile einer Vorteilszeile** - Speichern links, „Entfernen" rechts
 * abgesetzt: die einzige Handlung ohne Rueckweg, dieselbe Stelle wie in der
 * Bildzeile.
 */
.vorteil-knoepfe {
  display: flex; align-items: center; gap: 1rem; margin: 0;
}
.vorteil-knoepfe .ed-vorteilweg { margin-left: auto; color: var(--soft); }
/* **„Eintraege" nimmt die ganze Breite**: Was hier steht, sind
   Listen und ein Formular mit kurzen Feldern - kein Fliesstext. Die Lesebreite
   liesse rechts die Haelfte der Flaeche leer. */
.mappe-breit .mein-hinweis,
.mappe-breit .mappe-wahl,
.mappe-breit .mappe-vorschlag { max-width: none; }
/* Der Umkreis fuellt seine Spalte - er steht neben den Rubriken, und zwei
   Auswahlfelder in einer Reihe, von denen eines halb so breit ist, lesen sich
   als zwei verschiedene Bauteile. */

/* Die Auswahl der Mappe: Listen mit einer Handlung je Zeile. */
.mappe-unter, .mein-unter { margin: 2rem 0 .6rem; font-size: 1.05rem; }
/* **Die Zwischenueberschrift in einem Formular des Editors** - sie trennt
   einen Teil ab, der etwas anderes ist als der Rest („Nur fuer mich" in den
   Kerndaten einer Veranstaltung: was auf keiner Seite steht). */
.ed-unter { margin: 2rem 0 .4rem; font-size: 1.05rem; }
/* Das Suchfeld ueber der Liste ist ein Filter, kein Formular - schmal genug,
   dass es nicht wie eine Eingabe der Seite aussieht. */
/**
 * **Das Suchfeld nimmt die ganze Breite, die Vorschlaege legen sich darueber.**
 *
 * Die Liste stand **unter** dem Feld im Fluss und schob beim Tippen alles nach
 * unten - die Karte, die Liste, den halben Bildschirm. Ein Vorschlag ist aber
 * kein Inhalt, sondern ein Zwischenzustand: Er kommt, man waehlt, er geht.
 * Also liegt er darueber, mit Papier und Schatten, und nichts bewegt sich.
 */
.mappe-filterfeld { position: relative; max-width: none; margin-bottom: .8rem; }
/**
 * **Die zwei Regeln der Mappe nebeneinander** - wie weit sie schaut und was
 * sie auslaesst. Zwei gleich breite Spalten; unter 40 rem untereinander, wo
 * zwei Auswahlfelder nebeneinander zwei Kruemel waeren.
 */
.mappe-regeln {
  display: grid; grid-template-columns: 1fr 1fr auto; gap: 1rem;
  align-items: end;
}
.mappe-regeln .feld { margin: 0; }
@media (max-width: 40rem) {
  .mappe-regeln { grid-template-columns: 1fr; }
  .mappe-regeln .action { justify-self: start; }
}
/**
 * **Ein Aufklapper mit Haken** - die Mehrfachauswahl des Hauses.
 *
 * Kein `<select multiple>`: Das ist ein Kasten, in dem man mit gedrueckter
 * Taste klickt, auf dem Telefon gar nicht bedienbar und nirgends gestaltbar.
 * Ein `<details>` bringt Tastatur, Vorleseprogramm und das Auf und Zu vom
 * Browser mit; darin stehen gewoehnliche Haken.
 *
 * Zu sieht er aus wie ein Auswahlfeld - dieselbe Hoehe, dieselbe Kante, das
 * Dreieck rechts an der Stelle des Chevrons.
 */
.mehrwahl {
  border: 1px solid var(--line); border-radius: var(--feld-radius);
  background: var(--paper); position: relative;
}
/* **Dieselben Masse wie ein Auswahlfeld** - Hoehe, Innenabstand und der Platz
   rechts fuer das Zeichen stehen in der Grundregel fuer `select`; hier stehen
   sie noch einmal, weil ein `details` kein Formularfeld ist und nichts davon
   erbt. Zwei Felder nebeneinander, von denen eines 2,4 und das andere 2,8 rem
   hoch ist, sehen aus wie ein Fehler - und sind einer. */
.mehrwahl > summary {
  list-style: none; cursor: pointer;
  /* **Minus zwei Pixel**: Die Hoehe gilt fuer das Bauteil, und den Rahmen
     traegt hier das `details` aussen herum - anders als am Feld, wo er in der
     Hoehe steckt (`box-sizing: border-box`). */
  padding: .5rem 2rem .5rem .7rem; min-height: calc(var(--feld-hoehe) - 2px);
  display: flex; align-items: center; position: relative;
}
.mehrwahl > summary::-webkit-details-marker { display: none; }
/* In the dark the field has no ground of its own - `--paper` is darker than
   the card it stands on and drew a band behind it. The open list keeps its
   card ground: it lies over the content and must cover it. */
:root[data-theme="dark"] .mehrwahl { background: none; }
/**
 * **Derselbe Chevron wie an jedem Auswahlfeld** (`--chevron`), an derselben
 * Stelle und in derselben Groesse.
 *
 * Hier stand ein von Hand gezeichnetes Dreieck aus zwei Rahmenkanten: andere
 * Form, anderes Gewicht, andere Farbe (`--soft` statt der Schriftfarbe) - und
 * im Dunkelmodus haette es einzeln nachgezogen werden muessen. Das Token
 * bringt beide Fassungen mit. Gedreht wird es beim Aufklappen, wie an jedem
 * Aufklapper des Hauses; ein `select` dreht seines nicht, weil dort das System
 * die Liste zeichnet.
 */
.mehrwahl > summary::after {
  content: ""; position: absolute; right: .6rem; top: 50%;
  width: var(--chevron-groesse); height: var(--chevron-groesse);
  margin-top: calc(var(--chevron-groesse) / -2);
  background: var(--chevron) no-repeat center / var(--chevron-groesse);
  transition: transform .12s ease;
}
.mehrwahl[open] > summary::after { transform: rotate(180deg); }
.mehrwahl:hover { border-color: var(--soft); }
.mehrwahl > summary:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
/**
 * **Die Haken liegen ueber dem Inhalt, sie schieben ihn nicht.**
 *
 * Aufgeklappt wuchs das Feld und schob Karte und Liste nach unten - der Blick
 * musste dem Sprung folgen, und beim Zuklappen sprang alles zurueck. Als
 * Schicht bleibt die Zeile, in der man arbeitet, an ihrer Stelle. Dieselbe
 * Bauart wie die Vorschlaege der Suche darueber: eigener Grund, schwarze
 * Kante, Schatten - damit die Liste darunter sichtbar **darunter** liegt.
 */
.mehrwahl-liste {
  position: absolute; left: -1px; right: -1px; top: 100%; z-index: 20;
  display: grid; gap: .35rem;
  padding: .5rem .7rem .7rem;
  max-height: 18rem; overflow-y: auto;
  background: var(--card-ground);
  border: 1px solid var(--strong); box-shadow: var(--card-shadow);
}
/* Aufgeklappt traegt das Feld selbst die schwarze Kante - sonst stuende eine
   graue Linie zwischen Feld und Schicht. */
.mehrwahl[open] { border-color: var(--strong); }
.mappe-rubriken { display: flex; flex-wrap: wrap; gap: .4rem 1.4rem; }
.mappe-wahl { list-style: none; margin: 0 0 1.4rem; padding: 0; max-width: var(--text); }
/**
 * **Drei Spalten: Name, Ort, Handlung.**
 *
 * Als `flex` mit `space-between` haette der Ort seinen Platz zwischen Name und
 * Zeichen frei gewaehlt und staende in jeder Zeile woanders - eine Spalte ist
 * eine Spalte, wenn sie eine Kante hat.
 */
.mappe-wahl li {
  display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 1rem;
  padding: .5rem 0; border-bottom: 1px solid var(--line);
}
.mappe-wahl li > :first-child { min-width: 0; }
/* Der Ort ist die zweite Angabe, nicht die erste - leise wie ueberall. */
.mappe-ort { color: var(--soft); font-size: .9rem; }
.mappe-wahl .tab-unten { display: block; }
/**
 * **Hier steht der Papierkorb rot, nicht erst beim Zeigen.**
 *
 * Die Ausnahme von der Hausregel hat denselben Grund wie am stillgelegten
 * Aufsteller: In dieser Liste ist er das **einzige** Zeichen der Zeile, es gibt
 * also keine Spalte harmloser Zeichen, in der ein rotes vorher warnte. Die
 * Flaeche beim Zeigen kommt aus `.tab-zeichen`.
 */
.mappe-wahl .tab-weg { color: var(--state-stop-ink); }
/* Die Vorschlaege der Suche liegen unter dem Feld und schieben nichts. */
.mappe-vorschlag {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 20;
  list-style: none; margin: .25rem 0 0; padding: 0;
  max-height: 22rem; overflow-y: auto;
  background: var(--card-ground); border: 1px solid var(--strong);
  box-shadow: var(--card-shadow);
}
/* Eine Zeile je Eintrag: links Name und Angaben, rechts das Zeichen. */
.mappe-vorschlag li {
  display: flex; align-items: center; gap: .8rem;
  padding: .45rem .5rem .45rem .8rem;
  border-bottom: 1px solid var(--line);
}
.mappe-vorschlag li:last-child { border-bottom: 0; }
.mappe-vorschlag li:hover { background: var(--shade); }
.mappe-vorschlag-text { min-width: 0; }
.mappe-vorschlag .tab-unten { display: block; }
/**
 * **Das Auge kippt beim Zeigen.**
 *
 * Im Knopf liegen zwei Zeichen uebereinander: das, was **ist**, und das, was
 * der Klick daraus **macht**. Sichtbar ist immer nur eines - beim Zeigen und
 * im Fokus das zweite, in Schriftfarbe. So ist die Zeile in Ruhe eine Aussage
 * und unter der Hand eine Ankuendigung.
 */
.augenknopf { margin-left: auto; }
/* **`display: contents` und nicht `block`:** Die Huelle traegt nur den
   Schalter, das Zeichen selbst soll das Kind des Knopfes sein - sonst steht
   das SVG als Inline-Kasten in einer Zeile und sitzt um die Unterlaenge zu
   hoch im Quadrat. */
.augenknopf > span { display: contents; }
.augenknopf .auge-dann { display: none; }
.augenknopf:hover .auge-ist,
.augenknopf:focus-visible .auge-ist { display: none; }
.augenknopf:hover .auge-dann,
.augenknopf:focus-visible .auge-dann { display: contents; }
.augenknopf:hover, .augenknopf:focus-visible { color: var(--strong); }

/* Ein Feld, ein Knopf, eine Zeile. Der Knopf steht auf der Unterkante des
   Feldes (`align-items: end`), nicht auf der des Etiketts darüber. */
.form-zeile { display: flex; align-items: end; gap: .8rem; }
.form-zeile .feld { flex: 1 1 auto; margin: 0; }
.form-zeile .action { flex: none; }
@media (max-width: 34rem) {
  .form-zeile { flex-direction: column; align-items: stretch; }
  .form-zeile .action { width: 100%; }
}
/**
 * **Feld und Knopf als ein Stueck** (`.form-gruppe`).
 *
 * Eine Angabe, eine Handlung: „wie heisst das Schild" und „anlegen" gehoeren
 * zusammen, und ein Abstand dazwischen macht daraus zwei Dinge. Sie stossen
 * deshalb aneinander - der Knopf zieht sich um einen Pixel unter die Kante des
 * Feldes, damit zwischen ihnen **eine** Linie steht und nicht zwei.
 *
 * Darunter Luft: Ohne sie klebt die Zeile an der ersten Aufstellerkarte, und
 * das Anlegen sieht aus wie ein Teil der Liste.
 */
.form-gruppe { gap: 0; margin-bottom: 1.6rem; }
.form-gruppe .action { margin-left: -1px; }
@media (max-width: 34rem) {
  /* Untereinander braucht es den Versatz nicht - und den Abstand wieder. */
  .form-gruppe { gap: .6rem; }
  .form-gruppe .action { margin-left: 0; }
}
/* Die drei Abschnitte der Mappe stehen untereinander auf einer Tafel - die
   Ueberschrift trennt sie, nicht ein Rahmen: Es ist eine Seite, keine drei. */
/* Ohne Strich, wie `.konto-warum`: Die Tafel traegt die Trennung, der Abstand
   traegt die Gliederung. */
.mein-abschnitt {
  margin: 2.2rem 0 .6rem; font-size: 1.15rem;
}
.mein-abschnitt:first-child { margin-top: 0; }
/* Ein Aufsteller: das Quadrat links, die Angaben rechts. Der QR-Code ist so
   gross, dass ein Telefon ihn vom Bildschirm liest - man baut damit das Schild,
   bevor man es druckt. */
.qr-liste { list-style: none; margin: 0 0 1.4rem; padding: 0; max-width: var(--text); }
/**
 * **Die Kacheln der Mappe, wie der Gast sie sieht** - eine je Zeile, auf
 * grauem Grund wie eine Aufstellerkarte, mit denselben zwei Zeichen oben
 * rechts. Ein Klick auf die Karte oeffnet sie zum Bearbeiten, also traegt sie
 * den Zeiger und einen Fokusring.
 */
/* **Die Umkreiskarte ueber der Liste** - so hoch wie eine Nachbarkarte am
   Eintrag, mit dem Rahmen, den jede Karte im Haus traegt („bis hierher ist
   Karte"). Auf dem Telefon flacher: Dort steht die Liste darunter, und die
   will man sehen, ohne zu rollen. */
/* **Die Karte ist die Liste**, seit die Zeilen darunter weg sind - also
   bekommt sie die Hoehe einer Liste und nicht die eines Beiwerks. */
.mappe-karte {
  height: 28rem; margin: 0 0 1rem;
  border: 1px solid var(--line); border-radius: var(--card-radius);
  overflow: hidden;
}
@media (max-width: 34rem) {
  .mappe-karte { height: 20rem; }
}

.mein-kacheln { list-style: none; margin: 0 0 1.2rem; padding: 0; display: grid; gap: .8rem; }
.mein-kachel {
  position: relative;
  background: var(--shade); border-radius: var(--card-radius);
  padding: .9rem 1.1rem; padding-right: 5rem; cursor: pointer;
}
.mein-kachel h3 { margin: 0 0 .2rem; font-size: 1.05rem; }
.mein-kachel p { margin: 0; }
.mein-kachel-weg { font-family: var(--mono); font-size: .78rem; color: var(--soft); }
/* Air between the text and the address under it. */
.mein-kachel .mein-kachel-weg { margin-top: .5rem; }
/* A tile under "Start": the folder's tile itself, the corner over it. */
.mein-kachel-karte { position: relative; }
.mein-kachel-karte .mp-kachel { padding-right: 7.5rem; }
.mein-kachel-karte .qr-tun { top: .4rem; right: .4rem; z-index: 1; }
/* **The grip stands left of the tile, outside it** - the tile stays the
   guest's tile 1:1, and the grip is the one sign that the order means
   something, so it is always visible. `touch-action: none` sits on the grip
   alone: on the card it would take scrolling away from the phone. */
.mein-kachel-karte.ist-sortierbar {
  display: grid; grid-template-columns: 1.9rem minmax(0, 1fr); column-gap: .4rem;
}
.mein-kachel-karte.ist-sortierbar > :not(.mein-kachel-griff):not(.qr-tun) { grid-column: 2; }
.mein-kachel-karte.ist-sortierbar .qr-tun { right: .4rem; }
.mein-kachel-griff {
  grid-column: 1; grid-row: 1; align-self: center;
  display: grid; place-items: center;
  width: 1.9rem; height: 1.9rem; padding: 0;
  border: 0; background: none; color: var(--soft); cursor: grab;
  touch-action: none;
}
.mein-kachel-griff svg { width: .95rem; height: .95rem; display: block; }
.mein-kachel-griff:hover { color: var(--strong); }
.mein-kachel-griff:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
.mein-kachel-karte.sort-zieht .mein-kachel-griff { cursor: grabbing; }
/* `z-index` above: a paused tile is dimmed (`opacity`), and opacity makes the
   tile its own layer, painted after the corner that stands before it in the
   document - it covered the three buttons, and a paused tile could neither be
   started, edited nor deleted. */
.mein-kachel-karte.ist-aus .mp-kachel { opacity: .55; }
/* The paused state as a small monospace pill behind the title - a state of
   the machine, written like every other one. */
.mein-kachel-zustand {
  display: inline-block; vertical-align: 2px; margin-left: .4rem;
  padding: .25rem .75rem; border-radius: 999px; background: var(--shade);
  font-family: var(--mono); font-size: .68rem; font-weight: 400; letter-spacing: .04em;
  color: var(--soft); white-space: nowrap;
}
/* An own event carries three signs in the corner, a tile two. */
.mein-kachel:has([data-haustermin-bearbeiten]),
.mein-kachel:has([data-kachel-bearbeiten]) { padding-right: 7.5rem; }
.mein-kachel-inhalt h2 { margin: 0 0 .2rem; font-size: 1.05rem; }
.mein-kachel-inhalt p { margin: 0; }
/* An own event carries the row's thumbnail (`BFP.terminBild`, as the guest
   sees it in the folder: the picture, otherwise the calendar sheet) - the
   square on the left, the rest beside it. */
.mein-kachel:has(> .terminzeile-bild) { display: grid; grid-template-columns: var(--thumb) minmax(0, 1fr); column-gap: .9rem; }
.mein-kachel:has(> .terminzeile-bild) > :not(.qr-tun):not(.terminzeile-bild) { grid-column: 2; }
.mein-kachel > .terminzeile-bild { grid-column: 1; grid-row: 1 / span 4; }
/* The card is `--shade` already, the placeholder's own ground - so here the
   empty square takes paper, and it reads as a square as it does in the folder. */
.mein-kachel > .terminzeile-bild-leer { background: var(--paper); }
.mein-kachel:hover { background: color-mix(in srgb, var(--shade) 70%, var(--strong) 6%); }
.mein-kachel:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* Pausiert heisst: steht in der Mappe nicht - also leiser, wie ein
   stillgelegter Aufsteller. */
.mein-kachel.ist-aus { opacity: .55; }
.mein-kachel .plan-pille { background: var(--card-ground); }
/* Dieselbe Ecke an der Kachel - ein Bauteil, zwei Karten. */
.mein-kachel .qr-tun { top: .5rem; right: .6rem; }

/**
 * **Der Papierkorb an einer Aufstellerkarte ist rot** - dauerhaft, nicht erst
 * beim Zeigen.
 *
 * In einer Tabellenzeile steht er zwischen drei harmlosen Zeichen und wird
 * erst unter der Hand rot; hier steht er allein neben einem Schalter, und die
 * Karte, an der er haengt, ist ohnehin schon stillgelegt. Der naechste Klick
 * nimmt sie mit - das darf man sehen, bevor man hinzeigt.
 *
 * **Beim Zeigen ein weisses Quadrat**, nicht das uebliche `--paper` auf
 * `--shade`: Die Karte **ist** hier grau, also muss die Flaeche darauf heller
 * sein als sie - sonst zeigt das Zeigen nichts an.
 */
/**
 * **Die Vorschau des Aufstellers** - das PDF selbst in einem Rahmen, darunter
 * die zwei Wege hinaus. Die Hoehe haengt am Fenster und nicht am Blatt: Ein
 * Rahmen im Seitenverhaeltnis von A4 waere am Schirm hoeher als die Schicht.
 */
.qr-vorschau { display: grid; gap: 1rem; }
.qr-vorschau iframe {
  width: 100%; height: min(68vh, 44rem);
  border: 1px solid var(--line); background: var(--shade);
}
.qr-vorschau-tun { display: flex; gap: .7rem; margin: 0; flex-wrap: wrap; }

.qr-tun .tab-weg { color: var(--state-stop-ink); }
.qr-tun .tab-weg:hover, .qr-tun .tab-weg:focus-visible {
  color: var(--state-stop-ink); background: var(--card-ground); border-radius: 4px;
}
.qr-tun .tab-zeichen:hover, .qr-tun .tab-zeichen:focus-visible {
  background: var(--card-ground);
}

/**
 * **Die Karte eines Aufstellers steht auf grauem Grund, ohne Strich.**
 *
 * Sie liegt auf der weissen Tafel der Mappe - ein Rahmen darauf waere ein
 * Kasten in einem Kasten. `--shade` ist die leise Fuellung des Hauses, und der
 * Helligkeitsschritt trennt hier so gut wie eine Linie; dieselbe Ueberlegung
 * wie bei der Statistikkachel („ihre Grenze ist der Helligkeitsschritt").
 *
 * Die **runde Ecke** ist die des Backends (`--card-radius`, nur unter
 * `body.backend`) - draussen bleibt jede Ecke eckig.
 */
.qr-karte {
  position: relative;
  display: flex; gap: 1.1rem; align-items: flex-start;
  background: var(--shade); border-radius: var(--card-radius);
  padding: 1rem 1.1rem; margin-bottom: .8rem;
}
/* Die zwei Handlungen in der Ecke - dieselbe Stelle wie die Optionen einer
   Tabellenzeile, und derselbe Abstand zwischen den Zeichen. */
.qr-tun {
  position: absolute; top: .55rem; right: .6rem; margin: 0;
  display: flex; gap: .2rem;
}
/* **Groesser als in einer Tabellenzeile** - dort stehen vier Zeichen
   nebeneinander in einer Zeile von 44 px, hier zwei an einer Karte von
   7,5 rem. Das Ziel bleibt quadratisch, das Zeichen waechst mit. */
.qr-tun .tab-zeichen { width: 2rem; height: 2rem; }
.qr-tun .tab-zeichen svg { width: 1.35rem; height: 1.35rem; }
/**
 * **Um den Code herum bleibt Weiss stehen.**
 *
 * Ein QR-Code braucht seine **Ruhezone** - ohne sie findet eine Kamera die
 * drei Ecken schlechter, und auf grauem Grund stiess das Muster bisher direkt
 * an die Kante der Karte. Das Polster ist die Ruhezone; `#fff` bleibt `#fff`
 * und nicht `--paper`: Ein gedrucktes Schild ist weiss, auch im Dunkelmodus.
 */
.qr-bild {
  flex: none; width: 7.5rem; height: 7.5rem;
  background: #fff; padding: .5rem; border-radius: 4px;
}
/* **On the phone the card stays one row and the code shrinks with the
   screen** - proportionally, at most the 7.5 rem of a screen, so name,
   address, count and curve keep their room on the right. Nobody scans this
   code from their own screen anyway. */
@media (max-width: 34rem) {
  .qr-karte { gap: .8rem; }
  .qr-bild { width: clamp(4.5rem, 24vw, 7.5rem); height: clamp(4.5rem, 24vw, 7.5rem); padding: .35rem; }
  .qr-karte > :not(.qr-bild):not(.qr-tun) { min-width: 0; }
}
/* Die kleine Statistik unter den Zahlen des Aufstellers - dieselbe Kurve wie
   in den Mediadaten, nur schmaler: Sie steht neben einem Zeichen von 7,5 rem
   und soll es nicht ueberstimmen. */
/**
 * **Die Kurve steht links neben der Zahl**, als Quadrat wie in der Liste der
 * eigenen Eintraege - dieselbe Figur in derselben Groesse und derselben Farbe
 * (`--chart`). Eine Kurve, die je nach Ort anders aussieht, lernt man zweimal.
 *
 * Sie liegt auf `--paper` mit dem Schatten der Kachel; auf der grauen Karte
 * ist das ein Blatt und kein Loch - deshalb behaelt sie die Grundform und
 * bekommt hier nur ihren Platz.
 */
.qr-stat { display: flex; align-items: center; gap: .7rem; margin-top: .45rem; }
/* **Am Aufsteller etwas groesser** (49 px statt 40): Sie steht hier neben
   einer Zahl von 1,9 rem und nicht in einer Tabellenzeile - auf 40 px waere
   sie neben ihr ein Punkt. */
.qr-stat .mini-kurve { flex: none; width: 49px; height: 49px; }
.qr-bild svg { width: 100%; height: 100%; display: block; }
.qr-text { min-width: 0; }
/* Der Abstand kommt vom Block, nicht von jeder Zeile: Name, Adresse und Zahl
   gehoeren zusammen und sind keine drei Absaetze. */
.qr-text p { margin: 0; }
.qr-name { font-weight: 600; }
/* Die Adresse darf umbrechen, wo sie will - sie ist lang und soll die Karte
   nicht auseinanderziehen. */
/* Die Adresse und der Knopf, der sie mitnimmt - in einer Zeile, damit das
   Zeichen nicht unter dem Text steht wie eine eigene Handlung. */
.qr-adresse {
  display: flex; align-items: center; gap: .3rem;
  font-size: .82rem; color: var(--soft); overflow-wrap: anywhere;
}
.qr-adresse span { min-width: 0; }
.qr-adresse .tab-zeichen { flex: none; }
.qr-adresse .tab-zeichen svg { width: 1rem; height: 1rem; }
/* The copy button stands right of the discount code it takes along - the
   code is what one copies, so the sign belongs to it and not to the options. */
.code-copy-row { display: inline-flex; align-items: center; gap: .3rem; }
.code-copy-row .tab-zeichen { flex: none; }
/* A code is copied as one piece, so it is read as one: no break at the hyphen. */
.code-copy-row strong { white-space: nowrap; }
/* Die Zahl und ihr Wort - dieselbe Ordnung wie auf einer Statistikkachel:
   gross, was zaehlt; klein, was es benennt. */
.qr-wert {
  font-size: 1.9rem; line-height: 1.1; color: var(--strong);
  font-variant-numeric: tabular-nums;
}
/* **Eine Groesse fuer die ganze Zeile** - „Aufrufe" und „· 30 Tage" sagen
   zusammen, was die Zahl daneben zaehlt; zwei Groessen darin machten daraus
   zwei Angaben, von denen eine wichtiger aussieht. */
.qr-wort, .qr-spanne { font-size: .78rem; color: var(--soft); }
/* Ein stillgelegter Aufsteller bleibt lesbar - er haengt ja noch irgendwo. */
.qr-aus { opacity: .55; }

/* ---------------------------------------------------------------------------
   DIE GAESTEMAPPE - ein Bildschirm im Zimmer (05.09.2026)
   ---------------------------------------------------------------------------

   **Gebaut fuer eine Hand, nicht fuer einen Schreibtisch.** Sie wird im Stehen
   gelesen, von jemandem, der gerade angekommen ist: grosse Flaechen, wenig
   Text, nichts zum Zielen. Deshalb auch keine Navigation und kein Fuss der
   Huelle - es gibt hier nichts zu blaettern.

   Die Breite ist auf 34 rem begrenzt und mittig: Auf einem Tablet oder im
   Vorschaurahmen soll dieselbe Spalte stehen wie auf dem Telefon, nicht eine
   auseinandergezogene Fassung davon.

   Kein `border-radius` - Ecken sind Marke (Styleguide). */
/**
 * ===========================================================================
 * **EINE SEITE, AUS DER GAESTEMAPPE HERAUS AUFGEMACHT** (`?mappe=<slug>`)
 * ===========================================================================
 *
 * Sie zeigt ihren Inhalt und sonst nichts: keine Leiste, kein Fuss, keine
 * Lupe, keine Sprachwahl. Wer im Zimmer auf eine Empfehlung tippt, ist nicht
 * in den Guide gewechselt - er sieht sich an, was sein Haus ihm empfohlen hat,
 * und der einzige Weg, den er danach braucht, ist der zurueck.
 *
 * **Verborgen, nicht weggelassen:** Es ist dieselbe gebaute Seite, und sie
 * steht so auch unter ihrer eigenen Adresse. Ein zweites Markup dafuer waere
 * eine zweite Seite, die man mitpflegen muesste.
 */
html[data-mappe] .nav,
html[data-mappe] .foot,
html[data-mappe] .suchknopf,
html[data-mappe] #bottom-chrome { display: none; }
/* Ohne Leiste braucht die Seite den Platz darunter nicht. */
html[data-mappe] body { padding-top: 0; }
/**
 * **Die Leiste der Mappe steht hier am Dokument**, nicht in `#mappe` - also
 * braucht sie ihre Breite und ihre Seitenpolster selbst. In der Mappe holt
 * sie beides aus den negativen Raendern der Spalte.
 */
html[data-mappe] > body > .mp-kopf {
  margin: 0 0 1.2rem; padding-left: 1.1rem; padding-right: 1.1rem;
}
/**
 * **Der Zurueckknopf bleibt** - er ist in dieser Ansicht der einzige Weg.
 *
 * **Und er ist hier rund.** Im Guide ist das schwarze Quadrat die Form des
 * Hauses; in der Mappe ist es das nicht mehr - dort traegt der Kopf das
 * Signet **im Kreis**, und der Knopf schwebt auf dem Inhalt statt in einer
 * Leiste zu sitzen. Ein Quadrat, das frei ueber einer Liste liegt, liest sich
 * als abgeschnittene Flaeche; ein Kreis liest sich als Knopf. Es ist damit
 * dieselbe Begruendung wie bei den Rubrikfeldern daneben: Die runde Form ist
 * die **Form des Bauteils** und kein runder Kasten.
 */
html[data-mappe] a.backsquare#back { display: flex; border-radius: 999px; }

.mappe-seite { background: var(--paper); }
/**
 * **In der Vorschau kein Rollbalken** (05.09.2026) - und der Schwung eines
 * Telefons.
 *
 * Der Rollbalken des Rechners ist ein Streifen, den auf dem Geraet niemand
 * sieht; in einer Vorschau ist er ein Bauteil, das es dort nicht gibt.
 * `?vorschau=1` setzt deshalb `data-vorschau` am Dokument - die Regel greift
 * **nur** dort, nie beim Gast.
 *
 * `overscroll-behavior: contain` haelt das Rollen im Rahmen: Sonst rollt am
 * Ende der Mappe die Seite dahinter weiter, und das Backend springt weg.
 */
html[data-vorschau] { scrollbar-width: none; overscroll-behavior: contain; }
html[data-vorschau]::-webkit-scrollbar { width: 0; height: 0; }
html[data-vorschau] body { -webkit-overflow-scrolling: touch; }
/* Unten steht die Leiste, also endet der Inhalt darueber - `safe-area` fuer
   die Geraete mit einem Strich am unteren Rand. */
/**
 * **Oben kein Polster** - die schwarze Leiste faengt am Rand des Schirms an.
 *
 * Es stand hier 1,1 rem Papier, und die Leiste schob sich mit ihren negativen
 * Raendern zwar in die Breite, aber nicht nach oben: Zwischen Statuszeile und
 * Leiste blieb ein weisser Streifen, den man erst beim Rollen los wurde. Den
 * Abstand nach unten traegt die Leiste selbst (`margin-bottom`).
 */
#mappe {
  padding: 0 1.1rem calc(5.5rem + env(safe-area-inset-bottom));
}
/**
 * **Der Kopf ist eine Zeile, keine Begruessung** - Zeichen, Name, Ort.
 *
 * Er steht auf jedem der vier Reiter, also sagt er, **wo man ist**, und nicht
 * mehr: Der Gruss gehoert auf den Start und steht dort als Ueberschrift.
 */
/**
 * **Die Kopfleiste bleibt oben stehen** (`sticky`) - sie ist das Einzige, was
 * auf allen vier Reitern gleich bleibt, und sagt beim Rollen weiter, wessen
 * Mappe man liest. Ihr Papier ist das der Seite, damit unter ihr nichts
 * durchscheint; die Haarlinie darunter trennt sie vom Inhalt.
 */
/**
 * **Die Kopfleiste ist schwarz** - dieselbe Farbe wie die Leiste des Guide.
 *
 * Sie ist das Dach ueber vier Reitern und soll als eines zu sehen sein; auf
 * Papier war sie eine Zeile wie jede andere, und die Haarlinie darunter war
 * das Einzige, was sie von der Seite trennte. Schwarz traegt sie ausserdem das
 * Signet, ohne dass es wie ein Fleck im Text steht.
 *
 * Die Token werden **umgeschrieben statt der Kinder gefaerbt** (`--ink`,
 * `--soft`, `--strong`): Dieselbe Bauart wie beim Textblock der Buehne - was
 * darin steht, rechnet weiter mit den Namen, die es kennt.
 */
.mp-kopf {
  display: flex; align-items: center; gap: .8rem;
  position: sticky; top: 0; z-index: 4;
  /* **`width: auto` gegen die Hausregel `header { width: 100% }`:** Mit ihr
     blieb die Leiste so breit wie die Textspalte und rutschte durch die
     negativen Raender nur nach links - rechts fehlten die anderthalb
     Zentimeter, und die Linie darunter hoerte mitten im Bild auf. */
  width: auto; margin: 0 -1.1rem 1.2rem; padding: .7rem 1.1rem;
  background: var(--nav); border-bottom: 0;
  --ink: var(--nav-ink);
  --soft: color-mix(in srgb, var(--nav-ink) 70%, transparent);
  --strong: var(--nav-ink);
  color: var(--nav-ink);
}
/* In the dark the bar keeps its black: the tokens it draws with are turned
   back on the bar itself - ground, ink and the white of the circle - so the
   signet, the logo ground and the menu under it go along. */
:root[data-theme="dark"] .mp-kopf {
  --nav: var(--mappe-kopf);
  --nav-ink: var(--auf-bild-ink);
  --paper: var(--auf-bild-ink);
}
/**
 * **The tree in the circle** - on the rubric colour of the house, white sign
 * (`.mp-signet-rubrik`); without a rubric white paper, black sign, the
 * opposite of the bar. Rund, weil es ein Signet ist und kein Kasten: dieselbe
 * Ausnahme von `border-radius: 0` wie bei jedem Portraet des Hauses.
 */
.mp-signet {
  flex: none; width: 2.75rem; height: 2.75rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--paper); text-decoration: none;
}
.mp-signet:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: 3px; }
.mp-signet .signet-icon { width: 1.15rem; height: 1.55rem; fill: var(--nav); display: block; }
/* On the rubric of the house the tree turns white - the colour carries the
   circle, the sign stays the mark (`mappenKopf`). */
.mp-signet-rubrik { background: var(--signet-grund); }
.mp-signet-rubrik .signet-icon { fill: var(--auf-bild-ink); }
/* The house's logo fills the circle - cut round on upload. */
/* A logo may be smaller than its circle (transparent around it) - then the
   ground of the bar shows, as in the cropper. */
.mp-signet-logo { overflow: hidden; padding: 0; background: var(--nav); }
.mp-signet-logo.mp-signet-logo-hell { background: var(--nav-ink); }
.mp-signet-logo img { width: 100%; height: 100%; object-fit: cover; display: block; }
/**
 * **Die Hausregel fuer `header` gilt hier nicht.**
 *
 * `header > *` deckelt jedes direkte Kind auf die Rahmenbreite, schiebt es mit
 * `margin: auto` in die Mitte und gibt ihm 1,25 rem Innenabstand - das ist der
 * Kopf **einer Seite des Guide**, der eine Leiste ueber die volle Breite
 * traegt. Hier ist `header` die Zeile einer App: Zeichen, Name, Ort, links.
 * Ohne diese Zuruecknahme stand der Name mittig und um zwei Zentimeter
 * eingerueckt - und niemand haette den Grund im Stylesheet der Mappe gesucht.
 */
.mp-kopf > * { max-width: none; margin-left: 0; margin-right: 0; padding: 0; }
.mp-kopf-text { display: flex; flex-direction: column; min-width: 0; }
/* Rund wie jedes Portraet des Hauses - die dokumentierte Ausnahme von
   `border-radius: 0`, und aus demselben Grund: Der Kreis ist die Form des
   Bauteils. */
/**
 * **Das Hamburgerzeichen ist gezeichnet, nicht gesetzt** - drei Striche in
 * Schriftfarbe, 1,5 px stark, mit demselben Abstand wie das Zeichen der
 * Huelle. Es steht rechts aussen und traegt seinen Namen im `aria-label`.
 */
/* Das Kopfbild der Startseite - so breit wie die Mappe, ueber dem Gruss. */
.mp-hero {
  display: block; width: 100%; height: auto; aspect-ratio: 3 / 2;
  object-fit: cover; margin: 0 0 1.2rem;
}
/* Der Name ist die Ueberschrift dieser App - gross, in Schriftfarbe, und er
   bricht nicht um: Die Leiste ist eine Zeile. */
.mp-haus {
  margin: 0; font-size: 1.05rem; font-weight: 700; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mp-gruss { margin: 0 0 1.2rem; font-size: clamp(1.5rem, 5.5vw, 1.9rem); }
/* Die Ortszeile in der Monospace des Hauses (`--mono`, nicht das blanke
   `monospace`): So steht sie in derselben Schrift wie die Entfernung in der
   Liste darunter - beides Angaben, die niemand geschrieben hat. */
.mp-ort { margin: 0; color: var(--soft); font-family: var(--mono); font-size: .8rem; }
/* Die Kacheln des Hauses - was der Gast wissen will, bevor er nach draussen
   schaut. Ein Rahmen je Kachel, kein Schatten: Sie sind Zettel, keine Karten. */
.mp-kacheln { display: grid; gap: .8rem; margin-bottom: 2.2rem; }
/* From a tablet (46 rem - the narrowest iPad stands upright at 744 px) two
   columns: a tile is a card, and one card the width of a tablet is a banner.
   The tiles of a row stretch to the same height; "Kachel hinzufügen" in the
   backend preview takes the whole row. */
@media (min-width: 46rem) {
  .mp-kacheln { grid-template-columns: 1fr 1fr; }
  .mp-kachel-neu { grid-column: 1 / -1; }
}
/* A light radius - the house measure for a thing one holds (`--thumb-radius`,
   4 px, like a voucher): a tile is a note, not a box of the layout. */
.mp-kachel { border: 1px solid var(--line); border-radius: var(--thumb-radius); padding: .9rem 1rem; }
.mp-kachel h2 { margin: 0 0 .3rem; font-size: 1.05rem; }
.mp-kachel p { margin: 0 0 .3rem; }
/**
 * **A WLAN tile: network and password as a list of two** - the word small and
 * quiet on the left, the value on the right. The password is the pill of a
 * voucher code (`.gutschein-code`, monospace, 36 px): the thing one taps.
 */
.kachel-wlan { margin: .2rem 0 .5rem; display: grid; gap: .45rem; }
.kachel-wlan > div { display: grid; grid-template-columns: 5.5rem minmax(0, 1fr); align-items: center; gap: .6rem; }
.kachel-wlan dt { font-size: .85rem; color: var(--soft); }
/* Network and password both in monospace - both are typed character for
   character, and 0/O, l/1 must be told apart in each. */
.kachel-wlan dd { margin: 0; min-width: 0; overflow-wrap: anywhere; font-weight: 600; font-size: 1rem; font-family: var(--mono); }
.kachel-wlan dd { display: flex; align-items: center; gap: .4rem; }
/* The note of a WLAN tile: small text in a quiet info box. */
.kachel-hinweis {
  display: flex; align-items: flex-start; gap: .5rem; margin-top: .6rem;
  padding: .5rem .7rem; border-radius: var(--thumb-radius);
  background: var(--shade); color: var(--soft); font-size: .82rem; line-height: 1.4;
}
.kachel-hinweis svg { width: 1rem; height: 1rem; flex: none; margin-top: .05rem; color: var(--strong); }
.kachel-hinweis p { margin: 0 0 .2rem; }
.kachel-hinweis p:last-child { margin-bottom: 0; }
/* The password in a field - it reads as something to take, like an input
   with its value; the copy sign sits right behind it at the same height. */
/* It runs to the right edge of the tile (`flex: 1`), the copy sign behind it -
   so the WLAN rows end where the note below them ends. */
.kachel-pw {
  flex: 1 1 auto; min-width: 0;
  display: inline-flex; align-items: center; min-height: var(--regler-hoehe); box-sizing: border-box;
  padding: .2rem .7rem; border: 1px solid var(--line); border-radius: var(--thumb-radius);
  background: var(--shade);
  font-family: var(--mono); font-weight: 700; letter-spacing: .02em; overflow-wrap: anywhere;
}
/* The network name in the same field, on white: it is read and typed, not
   copied - the password is the one on the quiet ground with its copy sign. */
.kachel-netz { background: var(--paper); font-weight: 600; }
/* The copy sign behind the password - the height of every control (36 px),
   square, quiet until pointed at. */
.kachel-kopie {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: var(--regler-hoehe); height: var(--regler-hoehe); padding: 0;
  border: 1px solid var(--line); border-radius: var(--thumb-radius);
  background: var(--paper); color: var(--strong); cursor: copy;
}
.kachel-kopie svg { width: 1.05rem; height: 1.05rem; }
.kachel-kopie:hover { background: var(--shade); }
.kachel-kopie:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* The form of a tile: the WLAN fields only for a WLAN tile, link only for text. */
.vorteil-form:not([data-kachel-art="wlan"]) .kachel-nur-wlan,
.vorteil-form:not([data-kachel-art="wlan"]) .kachel-nur-wlan-inline,
.vorteil-form[data-kachel-art="wlan"] .kachel-nur-text { display: none; }
.kachel-nur-wlan { display: grid; gap: 0; }
.kachel-mono { font-family: var(--mono); letter-spacing: .02em; }
/* The tile editor in the backend: the button beside the label, the preview
   below as the guest sees it. */
.kachel-leiste { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
/* The option on the right of the bar is a pill - small, round at both ends,
   on the quiet ground; under the pointer the ground of an active pill. */
.kachel-fett {
  display: inline-flex; align-items: center; gap: .35rem; padding: .2rem .7rem;
  font: inherit; font-size: .8rem; color: var(--strong);
  border: 0; border-radius: 999px; background: var(--shade); cursor: pointer;
}
.kachel-fett:hover { background: var(--strong); color: var(--paper); }
.kachel-fett:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* Only in the backend's preview: a tile is something to edit; the guest never
   sees it (`data-vorschau`). **No padding is reserved for the pencil** - the
   tile keeps the width the guest sees, and the pencil lies on top of it: in
   the layer above everything in the tile, on paper, so a long title or the
   password pill runs under it instead of pushing it away. */
html[data-vorschau] .mp-kachel[data-kachel-vorschau-id] { position: relative; }
/* Scoped to the tile: `.tab-zeichen` comes later in this file with the same
   weight and would take size and background back. */
.mp-kachel .mp-kachel-bearbeiten {
  position: absolute; top: .4rem; right: .4rem; z-index: 2; width: 2rem; height: 2rem;
  background: var(--paper); border-radius: 4px;
}
.mp-kachel .mp-kachel-bearbeiten:hover,
.mp-kachel .mp-kachel-bearbeiten:focus-visible { background: var(--shade); }
.mp-kachel-neu {
  display: flex; align-items: center; justify-content: center; gap: .4rem; width: 100%;
  font: inherit; color: var(--soft); background: none; cursor: pointer;
  border: 1px dashed var(--soft); min-height: 3.5rem;
}
.mp-kachel-neu:hover, .mp-kachel-neu:focus-visible { color: var(--strong); border-color: var(--strong); }
.mp-nahes h2 { margin: 0 0 .2rem; font-size: 1.25rem; }
.mp-satz { margin: 0 0 .9rem; color: var(--soft); font-size: .9rem; }
#mp-suche { width: 100%; margin-bottom: .5rem; }
.mp-liste { list-style: none; margin: 0; padding: 0; }
.mp-liste li { border-bottom: 1px solid var(--line); }
/* Die ganze Zeile ist der Griff - auf einem Telefon zielt niemand auf ein Wort. */
.mp-liste a {
  display: flex; align-items: center; gap: .8rem;
  padding: .7rem 0; text-decoration: none; color: inherit;
}
/* Dieselbe Miniatur wie in jeder Zeile des Hauses (`--thumb`) - der Eintrag
   stand hier auf 64 px und der Termin daneben auf 44. */
.mp-liste img, .mp-kein-bild {
  width: var(--thumb); height: var(--thumb); flex: none; object-fit: cover;
  border-radius: var(--thumb-radius); background: var(--shade);
}
/* First the quiet line, then the name - with the same gap and the same size
   as in the event row (`--zeile-abstand`, `.terminzeile-wann`): the two lists
   stand in the same folder, one tab apart. */
.mp-text {
  min-width: 0; display: flex; flex-direction: column; flex: 1 1 auto;
  gap: var(--zeile-abstand);
}
.mp-zeile { font-size: .82rem; color: var(--soft); }
/* Ort (oder Datum) und die Entfernung in einer Zeile - der Text nimmt, was da
   ist, die Pille ihre Breite. */
.mp-meta { display: flex; align-items: center; gap: .45rem; min-width: 0; }
.mp-meta .mp-zeile, .mp-meta .mp-wann {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/**
 * **Die Entfernung ist eine Pille** - dieselbe Form wie `.plan-pille` im
 * Backend, und aus demselben Grund: Sie ist eine **Systemangabe**, eine
 * gerechnete Zahl, die kein Mensch geschrieben hat. Die Monospace auf leiser
 * Flaeche sagt genau das, und die fluchtenden Ziffern machen aus zwanzig
 * Zeilen untereinander eine Spalte.
 *
 * **Sie bricht nicht um:** „58,4 km" auf zwei Zeilen ist keine Zahl mehr,
 * sondern eine Zahl und ein Wort.
 */
.mp-km {
  /* **Rechts ausgerichtet**: Zwanzig Pillen untereinander sind nur dann eine
     Spalte, wenn sie an einer Kante stehen - sonst wandern sie mit der Laenge
     des Ortsnamens davor. */
  flex: none; white-space: nowrap; margin-left: auto;
  padding: .25rem .75rem; border-radius: 999px; background: var(--shade);
  font-family: var(--mono); font-size: .68rem; letter-spacing: .02em;
  font-variant-numeric: tabular-nums; color: var(--soft);
}
/* Der Satz und der Verweis stehen untereinander: „Zusammengestellt von …" ist
   eine Herkunftsangabe, „Den ganzen Guide ansehen" eine Handlung - in einer
   Zeile liest sich das eine wie die Fortsetzung des anderen. */
/* Portraet neben dem Satz, den es belegt - dieselbe Bauart wie die Zeile zum
   Absender in der Suchschicht, und aus demselben Grund: Ein Gesicht neben
   einem Satz sagt „da steht jemand dahinter", ein Kasten sagt „hier folgt ein
   Lebenslauf". Der Weg in den Guide steht als eigener Absatz darunter. */
.mp-fuss { margin-top: 2.4rem; color: var(--soft); font-size: .85rem; }
/* Unter „Start" ist er leer - und ein leerer Kasten mit Rand ist ein Abstand
   ohne Inhalt. */
.mp-fuss:empty { display: none; }
.mp-absender { display: flex; align-items: center; gap: .7rem; }
.mp-portraet {
  flex: none; width: 2.75rem; height: 2.75rem; border-radius: 50%;
  object-fit: cover; display: block;
}
.mp-fuss p { margin: 0; }
.mp-fuss p + p { margin-top: .35rem; }
/* Imprint and privacy: one quiet line, the two words side by side. */
.mp-fuss .mp-recht { display: flex; gap: 1.2rem; font-size: .8rem; }
.mp-fuss .mp-absender + .mp-recht { margin-top: 1.2rem; }
.mp-recht a { color: var(--soft); }
.mp-recht a:hover, .mp-recht a:focus-visible { color: var(--strong); }
.mp-leer { padding: 3rem 1.2rem; text-align: center; }

/**
 * **Die Leiste am unteren Rand** - vier Wege, die immer dastehen.
 *
 * `fixed` und nicht `sticky`: Sie soll beim Rollen liegen bleiben, und zwar
 * auch dann, wenn die Tafel kuerzer ist als der Bildschirm. In der Vorschau
 * des Backends ist der `iframe` der Bildschirm, also klebt sie dort am
 * unteren Rand des gezeichneten Telefons - genau richtig.
 *
 * Das Zeichen steht **ueber** dem Wort, nicht davor: In einem Feld von 90 px
 * ist nebeneinander kein Platz fuer beides, und ein Zeichen ohne Wort ist ein
 * Ratespiel. Der gewaehlte Weg traegt die Schriftfarbe, die drei anderen das
 * leise Grau - kein Fettdruck (Hausregel) und keine Flaeche.
 */
.mp-leiste {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 5;
  display: flex; justify-content: center;
  background: var(--paper); border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}
.mp-weg {
  flex: 1 1 0; min-width: 0; max-width: 9rem;
  display: flex; flex-direction: column; align-items: center; gap: .15rem;
  background: none; border: 0; cursor: pointer;
  padding: .55rem .2rem .6rem; color: var(--soft);
  font: inherit; font-size: .68rem; line-height: 1.2;
}
.mp-weg svg { width: 1.35rem; height: 1.35rem; }
.mp-weg span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.mp-weg[aria-current="page"] { color: var(--strong); }

/**
/**
 * **Die Rubriken links, der Umschalter rechts - eine Reihe.**
 *
 * **Beide sind 40 px hoch** (`--regler-hoehe`), und die Zahl steht am
 * Bauteil, nicht an der Reihe: Auf dem Telefon werden sie mit dem Daumen
 * getroffen, und dieselbe Hoehe gilt auf der Ergebnisseite und in der Reihe
 * der Startseite - dort steht keine solche Reihe drumherum.
 *
 * **Die Farbe traegt das Feld, nicht das Zeichen.** In Ruhe ein Hauch der
 * Rubrikfarbe auf Papier, darauf die gewoehnliche Schriftfarbe; gewaehlt und
 * unter dem Zeiger die volle Farbe mit weisser Zeichnung. Andersherum -
 * Zeichen in Rubrikfarbe auf hellem Grund - waere Entdecken im Dunkelmodus
 * dunkelblau auf fast schwarz: 2,1 : 1, also nichts. So stimmt es in beiden
 * Modi, weil `--strong` und `--paper` mitgehen und die gefuellte Flaeche eine
 * Flaeche ist, auf der es kein Hell und Dunkel gibt (`--auf-bild-ink`).
 *
 * **Und Gold traegt seine zweite Helligkeit**: `--rf-voll` liest
 * `var(--rubrik-eat-ink, var(--rubrik-eat))` - weiss auf `#c99a55` misst
 * 2,55 : 1 und faellt unter die 3 : 1 fuer eine Grafik, auf `#87602a` sind es
 * 5,62 : 1. Wer eine Rubrik dazubaut, braucht nichts zu tun.
 */
/**
 * **Sie klebt unter dem Kopf.** Die Reihe ist der Schnitt ueber die Liste -
 * Rubrik und Ansicht -, und wer dreissig Empfehlungen durchrollt, will ihn
 * genau dort aendern, wo er gerade steht. Das Suchfeld darueber rollt weg:
 * Es ist der Anfang einer Frage, nicht die Bedienung der Antwort.
 *
 * `top` ist die **gemessene** Hoehe des Kopfes (`--mp-kopfhoehe`, gesetzt von
 * `web/mappe.js` ueber einen `ResizeObserver`) - ein abgeschriebener Wert
 * waere dieselbe Hoehe ein zweites Mal, und bei einem langen Hausnamen, der
 * in zwei Zeilen bricht, die falsche. Der Rueckfall gilt, bis gemessen ist.
 *
 * Sie traegt eigenes Papier und geht bis an die Fensterkanten (dieselben
 * `-1.1rem` wie der Kopf) - sonst liefe die Liste seitlich an ihr vorbei.
 * Das Polster steht innen statt als Rand: Ein Rand gehoert nicht zum
 * klebenden Kasten und laege beim Anstossen ausserhalb.
 */
/**
 * **Sie bricht um, statt zu ueberlaufen.** Gemessen bei vier Rubriken: vier
 * Kreise von 40 px plus drei Luecken sind 175 px, der Umschalter 166, die
 * Luecke dazwischen 8 und die Seitenpolster 35 - zusammen **383 px**. Ein
 * iPhone bietet 375, ein schmales Geraet 360, und ohne Umbruch stand darunter
 * ein waagerechter Rollbalken auf einer Seite, die sonst keinen hat. Mit dem
 * Umbruch fallen die Rubriken in die erste Zeile und der Umschalter rechts in
 * die zweite; `margin-inline-start: auto` haelt ihn dort, wo er auch in einer
 * Zeile steht.
 */
.mp-filterreihe {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  position: sticky; top: var(--mp-kopfhoehe, 3.6rem); z-index: 3;
  background: var(--paper);
  margin-block: .25rem .35rem; margin-inline: -1.1rem;
  padding: .55rem 1.1rem;
  transition: box-shadow .18s ease;
}
/**
 * **Der Schatten kommt erst, wenn sie klebt.** Im Fluss ist die Reihe eine
 * Zeile wie jede andere; erst wenn Inhalt **unter** ihr durchlaeuft, ist sie
 * eine Ebene darueber - und genau das sagt der Schatten. Dauerhaft gesetzt
 * behauptete er die Ebene auch dann, wenn die Seite ganz oben steht.
 *
 * Gesetzt wird `data-klebt` von einem `IntersectionObserver` in `mappe.js`:
 * Ein reines `position: sticky` sagt dem Stylesheet nicht, ob es gerade
 * greift.
 */
/* In the flow a hairline like the separators of the list below (`--line`);
   stuck, the shadow takes over and the line gives way - two edges at once
   would be one too many. */
/* Inset like them: the row reaches the edge (negative margin), the line
   stands on the text column, where the separators of the list stand. */
.mp-filterreihe::after {
  content: ""; position: absolute; left: 1.1rem; right: 1.1rem; bottom: 0;
  border-bottom: 1px solid var(--line); transition: opacity .18s ease;
}
.mp-filterreihe[data-klebt="1"]::after { opacity: 0; }
/* A soft shadow always, a stronger one once it is stuck - same shape, only
   the depth changes, so the row seems to lift rather than change. */
.mp-filterreihe { box-shadow: 0 4px 14px -6px rgb(0 0 0 / .15); }
.mp-filterreihe[data-klebt="1"] { box-shadow: 0 4px 14px -6px rgb(0 0 0 / .25); }
@media (prefers-reduced-motion: reduce) {
  .mp-filterreihe { transition: none; }
}
/**
 * **Der Abstand sitzt an der Reihe, nicht am Umschalter.** Am Umschalter
 * rechnete er in die Hoehe der Reihe hinein - und die Rubrikfelder, die sich
 * genau danach strecken, standen damit doppelt so hoch wie er selbst. **Nur
 * die zwei waagerechten Raender** und nicht `margin` als Kurzform: Die
 * Grundregel schiebt ihn mit `margin-inline-start: auto` nach rechts, und die
 * Kurzform setzte diesen Rand auf null.
 */
.mp-filterreihe .viewtabs { margin-block: 0; }
.rubrikfelder { display: flex; gap: .3rem; }
.rubrikfeld {
  display: inline-flex; align-items: center; justify-content: center;
  /**
   * **Rund, und das ist eine Form und kein runder Kasten** - dieselbe
   * Begruendung wie beim Suchschlitz, den Portraets, dem Plus auf der
   * Zeilenlinie und dem Einwilligungsschalter. Ein Feld steht hier **in** der
   * Reihe eines runden Reglers, gleich hoch und gleich laut; eckig daneben
   * lasen sich vier Kacheln und eine Pille als zwei Bauteile. Ein Zeichen in
   * einem Kreis ist ausserdem die Form, die das Haus fuer eine **Marke**
   * schon hat: das Signet im Kopf der Mappe.
   */
  height: var(--regler-hoehe); aspect-ratio: 1; padding: 0; border-radius: 999px;
  /**
   * **A field left out is an outline** - ring and sign in the category
   * colour on paper, drawn like a pin on the interactive map and like the
   * quick links of the search layer. The full surface means "in the cut".
   * In dark mode ring and sign are mixed half with `--strong` (pure,
   * Entdecken measures 2.1 : 1 on the dark paper); the full surface stays
   * pure.
   */
  --rf-linie: var(--rf-voll);
  border: 1px solid var(--rf-linie); background: var(--paper);
  color: var(--rf-linie); cursor: pointer;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
:root[data-theme="dark"] .rubrikfeld { --rf-linie: color-mix(in srgb, var(--rf-voll) 50%, var(--strong)); }
.rubrikfeld:hover,
.rubrikfeld[aria-pressed="true"] {
  background: var(--rf-voll); border-color: var(--rf-voll); color: var(--rf-auf, var(--auf-bild-ink));
}
/* **Nothing chosen means everything is shown - so everything stands full.**
   The outline is the state of a field that is **left out**: it appears only
   once one field is chosen, and then says "not in the cut". A row of
   outlines at rest looked switched off while it showed everything. */
.rubrikfelder:not(:has(.rubrikfeld[aria-pressed="true"])) .rubrikfeld {
  background: var(--rf-voll); border-color: var(--rf-voll); color: var(--rf-auf, var(--auf-bild-ink));
}
/* **The field without a category colour** (the events: `--strong`) is white
   in dark mode, and a white sign on it vanished. On its full surface the sign
   takes the paper colour - black on white in the dark, white on black in the
   light. */
.rubrikfeld[data-ton="strong"] { --rf-auf: var(--paper); }
.rubrikfeld:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* **The sign is two thirds of the circle, and it says so in the circle's
   unit.** The circle stands on `--regler-hoehe`; a sign with a size of its
   own would grow or shrink against it. */
.rubrikfeld-icon { width: calc(var(--regler-hoehe) * 2 / 3); height: calc(var(--regler-hoehe) * 2 / 3); flex: none; }
@media (prefers-reduced-motion: reduce) { .rubrikfeld { transition: none; } }
/**
 * Ohne Flaechen bleibt nur die Zeichnung - der gewaehlte Zustand braucht dann
 * einen Rahmen, sonst sagt nichts mehr, welche Rubrik gilt.
 */
@media (forced-colors: active) {
  .rubrikfeld[aria-pressed="true"] { outline: 2px solid; outline-offset: -3px; }
}

.mp-karte { height: 60vh; min-height: 18rem; border: 1px solid var(--line); }

/* Der Termin: Datum links in fester Spalte, wie im Kalender des Guide. */
/* Das Datum steht als erste Zeile im Textblock - ueber dem Namen, leise und
   mit fluchtenden Ziffern. */
.mp-wann {
  font-size: .8rem; color: var(--soft); font-variant-numeric: tabular-nums;
}
/**
 * **Ein Name bleibt in einer Zeile** - in jeder Liste dieser App: Termine,
 * Empfehlungen, Vorteile.
 *
 * „Schwarzwaldpokal – Weltcup Nordische Kombination" lief ueber drei Zeilen
 * und machte aus einer Zeile einen Absatz; bei zwanzig davon untereinander
 * verliert die Liste ihre Ordnung, und das Bild links steht neben einem Block
 * statt neben einer Zeile. Gekuerzt sagt der Anfang, worum es geht - den
 * ganzen Namen sagt die Seite dahinter.
 *
 * **Die Groesse bleibt die der Zeile.** Der Name ist das, was man liest, und
 * er steht so gross wie ueberall sonst. Klein gesetzt passte er zwar ganz
 * hinein, war dann aber die leiseste Angabe einer Zeile, in der er die
 * lauteste sein soll: Das Kuerzen loest das Problem, nicht das Schrumpfen.
 */
.mp-liste strong {
  display: block;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* The perks tab: blocks set apart by air, businesses by a hairline. */
.mp-vorteil-betrieb + .mp-vorteil-betrieb {
  margin-top: 1.4rem; padding-top: 1.1rem; border-top: 1px solid var(--line);
}
/* The row of a business is the link and the heading of its vouchers. */
.mp-vorteil-kopf {
  display: flex; min-height: 44px; margin-bottom: .6rem; color: inherit; text-decoration: none;
}
.mp-vorteil-kopf:hover strong { text-decoration: underline; text-underline-offset: .18em; }
/* "Bei uns" and "In der Nähe" are the two parts of the tab (on "Vorteile" and
   on "Was ist los") - one level above the businesses. So they stand larger and carry a full line in the strong
   colour, where a business only gets a hairline: two kinds of separation for
   two levels. */
.mp-unter {
  margin: 0 0 .9rem; padding-bottom: .45rem;
  font-size: 1.3rem; font-weight: 700; border-bottom: 2px solid var(--strong);
}
.mp-vorteil-block + .mp-vorteil-block { margin-top: 2.4rem; }
/* The same two parts on "Was ist los": the house's own events, then the area. */
.mp-termine-haus + .mp-termine-umgebung { margin-top: 2.4rem; }

/**
 * **The folder takes the whole width of the device, on every device.**
 *
 * It is an app, opened from a code on a counter - on a tablet or a laptop in
 * the room just as on a phone. A column of 34 rem centred on a wide screen
 * looked like a phone page left inside a larger one, so the column and the
 * bar at the bottom both run from edge to edge. It stays **one** column: each
 * of the four tabs is one thing, and two columns would tear it apart.
 */
@media (min-width: 60rem) {
  .mp-gruss { font-size: 2.1rem; }
}

/* ---------------------------------------------------------------------------
   DIE VORSCHAU IM BACKEND - dieselbe Mappe, in einem Telefon
   ---------------------------------------------------------------------------

   **Sie zeigt nicht ein Bild der Mappe, sondern die Mappe.** Ein Rahmen um
   einen `iframe` mit derselben Adresse, die auf dem Aufsteller steht: Was der
   Wirt hier sieht, ist Zeile fuer Zeile das, was sein Gast sieht - inklusive
   der Kachel, die er gerade gespeichert hat.

   375 x 780 sind die Masse eines gewoehnlichen Telefons in CSS-Pixeln - die
   Breite, unter der die meisten Geraete liegen, und damit der Fall, fuer den
   man baut. Der dunkle Rahmen ist kein Spielzeug-Handy mit Knopf und Kamera,
   sondern eine Kante - sie sagt „so breit ist es", mehr braucht es nicht. */
/**
 * **Zwei Bilder, eine Zeile je Bild** - die Vorschau links in der Form, in der
 * es spaeter steht (rund fuer das Zeichen, breit fuer das Kopfbild), rechts
 * der Name, der Satz dazu und der Knopf.
 *
 * Die Vorschau **zeigt die Form** und nicht nur die Datei: Ein rundes Logo
 * neben einem quadratischen Kasten sagt nicht, dass es beschnitten wird.
 */
/* Head image and logo side by side, each a compact column: the preview in
   its form, the name, one short line, the two actions as quiet links. */
.mp-bilder {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: 2rem 4.5rem;
}
/* **Every preview sits in a slot of the same width** (6 rem, the head
   image's), the round logo centred in it - so the names beside them start on
   one line, with a picture or without. */
.mp-bild-feld {
  display: grid; grid-template-columns: 6rem minmax(0, 1fr); align-items: center; gap: .9rem;
}
.mp-bild-feld > .mp-bild-schau { justify-self: center; }
/* The start part is no card: greeting and pictures stand on the ground, one
   field each, with the tiles under them. */
.mp-start-kopf { max-width: 46rem; margin: 0 0 1.6rem; }
.mp-bilder-feld { margin: 0; }
.mp-bilder-feld > .feld-hint { display: block; }
.mp-bild-schau {
  flex: none; overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  background: var(--shade); color: var(--soft); font-size: .78rem;
}
.mp-bild-schau.ist-breit { width: 6rem; height: 4rem; border-radius: var(--feld-radius); }
.mp-bild-schau.ist-rund { width: 4rem; height: 4rem; border-radius: 50%; }
.mp-bild-schau.ist-quadrat { width: 4rem; height: 4rem; border-radius: var(--thumb-radius); }
.haustermin-bild { margin: 0 0 1rem; }
/* The greeting: the field and its button in one row. */
/* The greeting: the button always right beside the field, on its line - the
   hint below both. */
.mp-gruss-form { margin: 0 0 1.4rem; }
.mp-gruss-form .feld { margin: 0; }
.mp-gruss-reihe { display: flex; align-items: stretch; gap: .6rem; }
.mp-gruss-reihe input { flex: 1 1 auto; min-width: 0; }
/* The button keeps its own width here, also on the phone: below 34 rem every
   `.action` takes the full width, and in this row that squeezed the field
   beside it to a sliver (the discount code under "Abonnement"). */
.mp-gruss-reihe .action { flex: none; width: auto; }
.mp-gruss-form .feld-hint { display: block; }
.mp-bild-schau.ist-rund:not(.ist-leer) { background: var(--nav); }
.mp-bild-schau.ist-rund.ist-hell:not(.ist-leer) { background: var(--nav-ink); border: 1px solid var(--line); }
.mp-bild-schau img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Ohne Bild steht das Wort da - eine leere Flaeche sagt nicht, dass hier etwas
   hingehoert. */
.mp-bild-schau.ist-leer { border: 1px dashed var(--line); }
.mp-bild-text { min-width: 0; flex: 1; }
.mp-bild-text h3 { margin: 0; font-size: .95rem; }
.mp-bild-text .feld-hint { margin: .1rem 0 .35rem; }
.mp-bild-tun { display: flex; align-items: center; gap: .9rem; margin: 0; font-size: .9rem; }
.mp-bild-tun label { cursor: pointer; }
/* The input is hidden, its label is the target - so the focus ring goes there. */
.mp-bild-tun label:has(+ input:focus-visible) { outline: 2px solid var(--strong); outline-offset: 2px; }

/**
 * **Der Kopf einer Reihe: Ueberschrift links, Umschalter rechts.**
 *
 * Er traegt beide auf einer Grundlinie und bricht um, wenn es eng wird - dann
 * steht der Umschalter unter der Ueberschrift und weiter rechts, weil er
 * seinen eigenen Rand mitbringt (`margin-inline-start: auto`).
 */
.reihe-kopf {
  display: flex; align-items: baseline; gap: 1rem; flex-wrap: wrap;
  margin: 2.4rem 0 1rem;
}
.reihe-kopf h2 { margin: 0; }
/**
 * **Der Schnitt der Reihe** - links die Rubriken, rechts der Umschalter, und
 * beide rechts vom Titel. `margin-inline-start: auto` sitzt jetzt an der
 * Reihe: Am Umschalter allein schob es ihn nach rechts, die Rubrikfelder aber
 * blieben am Titel kleben.
 */
.reihe-schnitt {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin-inline-start: auto;
}
/**
 * **Wird es eng, verliert der Umschalter seine Zeichen** - nicht die Reihe
 * ihre Zeile.
 *
 * Die Zahl der Rubrikfelder haengt am Bestand (drei bis sechs), also gibt es
 * keine Breite, ab der es kippt - `home.js schnittMessen` sieht nach, ob die
 * Reihe umgebrochen ist, und setzt `data-eng`. Die zwei Woerter tragen die
 * Aussage; das Zeichen davor ist die Zugabe, und eine Zugabe geht zuerst.
 * Bleibt es danach immer noch zu breit, bricht die Reihe um - das ist der
 * Rueckfall und kein Fehler.
 */
[data-eng="1"] .viewtabs .nav-icon { display: none; }
.reihe-kopf .viewtabs { margin: 0; }
/* Die Karte der Reihe - so hoch wie zwei Kachelreihen, damit der Wechsel die
   Seite nicht umbaut. */
.reihe-karte { height: 32rem; border: 1px solid var(--line); }
@media (max-width: 40rem) {
  .reihe-karte { height: 24rem; }
}

.mp-vorschau {
  display: grid; gap: 1rem; justify-items: start; margin: 0 0 2rem;
  /* As wide as the frame, not as the column - so "centred" below means
     centred under the device, whichever of the three it is. */
  width: fit-content; max-width: 100%;
}
/**
 * **Ein Telefon, keine Kiste** (05.09.2026).
 *
 * Der Rahmen war ein Rechteck mit 10 px schwarzem Rand - richtig im Mass,
 * falsch in der Aussage: Er sah aus wie ein Kasten auf der Seite, nicht wie
 * das Geraet, auf dem der Gast liest. Jetzt die Silhouette: runde Ecken,
 * schwarzer Rand, die Kerbe oben und der Strich unten.
 *
 * **Gezeichnet, nicht fotografiert** - kein Bild eines bestimmten Geraets:
 * Ein abgebildetes iPhone waere fremdes Produktdesign in unserer Oberflaeche
 * (und in ein paar Jahren ein altes Modell). Was hier zaehlt, ist die Form:
 * „so breit ist es, so hoch, und die Ecken sind rund".
 *
 * Die runden Ecken sind eine **Ausnahme von der Marke** (`border-radius: 0`)
 * mit demselben Grund wie beim Suchschlitz: Das Bauteil bildet etwas ab, das
 * es in der Welt gibt, und ein Telefon mit rechten Ecken bildet nichts ab.
 */
/**
 * **Der Rahmen hat drei Maße** - Telefon, Tablet, Schirm.
 *
 * 375 x 780 ist ein gewoehnliches Telefon, 834 x 1000 ein Tablet im Hochformat
 * (iPad in CSS-Pixeln, unten beschnitten: Ein Rahmen von 1112 px passt auf
 * keinen Bildschirm, auf dem man gleichzeitig arbeitet), 1280 x 800 ein
 * Laptop. **Die Breite ist das, worauf es ankommt** - an ihr haengt, ob die
 * Mappe in einer Spalte steht oder in zweien (ab 60 rem).
 *
 * **Die Maße stehen als Token**, weil zwei Stellen sie brauchen: der Rahmen
 * selbst und das Feld darunter, das seinen verkleinerten Platz freihaelt.
 *
 * Die Kerbe und der Strich fallen ab dem Tablet weg - das eine hat keine, das
 * andere keinen.
 */
/**
 * **Die Zahl ist der Schirm, nicht das Geraet.** 375 x 780 ist die Flaeche,
 * auf der die Mappe steht - das, was ein Browser `innerWidth` nennt und
 * wonach jede Breitenregel im Stylesheet fragt. Die Fassung kommt aussen dazu
 * (`--mp-rand`), sonst waere die Vorschau um zweimal zwoelf Pixel zu schmal
 * und zeigte die Mappe eine Spur enger, als sie steht.
 */
/* The width comes from the grip (`mappeBreiteSetzen`, inline on the element);
   375 is the phone the folder is built for and the starting point. The height
   stays: a frame that grows taller while dragging sideways would move the
   grip away from under the pointer. */
.mp-vorschau { --mp-breite: 375px; --mp-hoehe: 780px; --mp-rand: 12px; --mp-zoom: 1; }
.mp-vorschau[data-geraet="tablet"] .mp-geraet { border-radius: 1.6rem; }
.mp-vorschau[data-geraet="tablet"] .mp-geraet::before { display: none; }

/**
 * **The grip on the right edge** - a short bar beside the frame, the form every
 * resizable pane has. Round like the switch and the slider track, and for the
 * same reason: a bar that is pulled is a handle, not a box. Its hit area is
 * wider than its ink (`::before`), because a 6 px target is a line one hits
 * or not.
 */
.mp-geraet-feld { position: relative; }
.mp-griff {
  position: absolute; top: 50%; right: -1.1rem; transform: translateY(-50%);
  width: 6px; height: 3.5rem; border-radius: 999px;
  /* At rest the quiet fill of the house (`--shade`), active `--strong`. */
  background: var(--shade); cursor: ew-resize; touch-action: none;
}
.mp-griff::before { content: ""; position: absolute; inset: -.6rem -.7rem; }
.mp-griff:hover, .mp-vorschau[data-zieht] .mp-griff { background: var(--strong); }
.mp-griff:focus-visible { outline: 2px solid var(--strong); outline-offset: 3px; }
/* While dragging, the page inside must not take the pointer. */
.mp-vorschau[data-zieht] iframe { pointer-events: none; }
.mp-vorschau[data-zieht] { cursor: ew-resize; user-select: none; }
/* Device and sign side by side, standing on the same line like on a table;
   when the device is dragged wide, the sign moves below it. */
.mp-vorschau-reihe { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 1.5rem 3rem; }
.mp-vorschau-geraet { display: grid; gap: 1rem; justify-items: center; }

/**
 * **The sign on the counter** (`mappeAufsteller`) - a black board with the
 * contour lines, the sentence in white, the tree pin in the house's rubric
 * colour, and hanging from its tip a small square in the same colour carrying
 * the QR code. The board stays black in both modes: it pictures a printed sign,
 * not a surface of the backend. The code keeps a white field with a wide quiet
 * zone (four modules, `data-qr-rand`) - dark modules on a light ground, with
 * room around them, are what every camera reads. A foot below makes it a
 * stand and not a poster.
 */
.mp-aufsteller { margin: 0; display: grid; justify-items: center; }
/* Stand and notice side by side, standing on the same line. */
.mp-schilder { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 1.5rem 2.5rem; }
/**
 * **The A4 notice** - the same sign in the proportion of A4 and a size larger:
 * it hangs on a post and is read from a few steps away. Four holes near the
 * corners for the cable ties, each with a ring as an eyelet would have.
 */
.mp-schild.mp-aushang {
  position: relative; width: 20rem; aspect-ratio: 210 / 297;
  align-content: center; padding: 2rem 1.8rem;
}
.mp-aushang .mp-schild-marke svg { width: 6.5rem; }
.mp-aushang .mp-schild-satz { font-size: 1.3rem; margin-bottom: 1.4rem; }
.mp-aushang .mp-schild-nadel { width: 6.5rem; }
.mp-aushang .mp-schild-sticker { width: 5.75rem; }
.mp-aushang .mp-schild-adresse { font-size: .38rem; }
/* The notice has no foot, so its caption keeps the stand's distance itself
   (foot .7 rem + .9 rem) - both captions stand on one line. */
.mp-schild.mp-aushang + .mp-masse { margin-top: 1.6rem; }
.mp-loch {
  position: absolute; width: .7rem; height: .7rem; border-radius: 50%;
  background: var(--paper); box-shadow: 0 0 0 .18rem color-mix(in srgb, var(--auf-bild-ink) 55%, transparent);
}
.mp-loch:nth-of-type(1) { top: .9rem; left: .9rem; }
.mp-loch:nth-of-type(2) { top: .9rem; right: .9rem; }
.mp-loch:nth-of-type(3) { bottom: .9rem; left: .9rem; }
.mp-loch:nth-of-type(4) { bottom: .9rem; right: .9rem; }
.mp-schild {
  width: 16rem; box-sizing: border-box; padding: 1.6rem 1.4rem 1.8rem;
  display: grid; justify-items: center;
  /* Black with the contour lines of the house (white at 15 %, made for a dark
     ground - the same file as in the foot of every page). Dark in both modes:
     it pictures a printed sign. */
  background-color: var(--videogrund); color: var(--auf-bild-ink);
  background-image: url("hoehenlinien.svg");
  background-repeat: no-repeat; background-size: cover; background-position: center;
  border-radius: .5rem; box-shadow: 0 10px 30px rgb(0 0 0 / .18);
}
.mp-schild-satz {
  margin: 0 0 1.3rem; text-align: center;
  font-size: 1.15rem; font-weight: 700; line-height: 1.25; text-wrap: balance;
}
/* The pin: its tip rests on the upper edge of the square. */
.mp-schild-nadel { display: block; width: 6rem; aspect-ratio: 242 / 308; color: var(--schild-farbe); }
.mp-schild-nadel svg { display: block; width: 100%; height: 100%; }
.mp-schild-sticker {
  display: block; width: 4.5rem; margin-top: -.15rem;
  box-sizing: border-box; padding: .3rem; background: var(--schild-farbe); border-radius: .3rem;
}
/* The white field: the code with its quiet zone, and the short address under it. */
.mp-schild-weiss {
  display: grid; justify-items: center; background: #ffffff; border-radius: .15rem;
  padding-bottom: .2rem;
}
.mp-schild-qr { display: block; width: 100%; aspect-ratio: 1; }
.mp-schild-qr svg { display: block; width: 100%; height: 100%; }
.mp-schild-adresse {
  margin-top: -.15rem; font-family: var(--mono); font-size: .3rem; line-height: 1.2;
  color: #000000; white-space: nowrap;
}
.mp-schild-marke { display: block; margin-bottom: 1.1rem; line-height: 0; }
/* The domain at the foot of the sign - in the type of the sentence above,
   small and white on the board: an address to read, not a system value. */
.mp-schild-domain {
  margin-top: 1.1rem; font-size: .5rem; font-weight: 600; letter-spacing: .02em;
  color: var(--auf-bild-ink); white-space: nowrap;
}
.mp-aushang .mp-schild-domain { margin-top: 1.4rem; font-size: .62rem; }
/* The wordmark of the bar (272 x 32), small and white on the black board. */
.mp-schild-marke svg { display: block; width: 5.5rem; height: auto; fill: currentColor; }
.mp-schild-fuss {
  display: block; width: 9rem; height: .7rem; margin-bottom: .9rem;
  background: color-mix(in srgb, var(--videogrund) 80%, var(--paper));
  border-radius: 0 0 .35rem .35rem;
}
.mp-aufsteller .mp-masse { justify-self: center; }

/* The width under the frame, on its axis - a measured value, in monospace. */
.mp-masse {
  justify-self: center; margin: 0;
  font-family: var(--mono); font-size: .8rem; color: var(--soft);
  font-variant-numeric: tabular-nums;
}

/**
 * **Was nicht hineinpasst, wird verkleinert - nicht beschnitten.**
 *
 * Ein Schirm von 1280 px ist breiter als die Flaeche, auf der er steht: Neben
 * Navigation und Rand bleiben in einem Fenster von 1280 px noch rund 900.
 * Waagerecht rollen waere die Alternative, und dann sieht man nie die ganze
 * Seite - genau das, wofuer die Vorschau da ist.
 *
 * `transform: scale` laesst den Rahmen **innen** so breit, wie er ist: Die
 * Mappe darin rendert als 1280er Seite und zeigt ihre zwei Spalten. Ein
 * kleinerer `iframe` waere eine kleinere Seite und damit die falsche Antwort.
 *
 * Den Faktor misst das Skript (`mappeZoom`), weil CSS keine Flaeche kennt, in
 * die es etwas einpassen koennte. Das Feld darunter haelt den **verkleinerten**
 * Platz frei, sonst stuende unter einem geschrumpften Rahmen die volle Hoehe
 * als Luft.
 */
.mp-geraet-feld {
  width: calc((var(--mp-breite) + 2 * var(--mp-rand)) * var(--mp-zoom));
  height: calc((var(--mp-hoehe) + 2 * var(--mp-rand)) * var(--mp-zoom));
  max-width: 100%;
}
/* Die Tafel der Vorschau darf breiter werden als eine Lesespalte - ein Tablet
   von 834 px passt sonst nicht hinein. */
#mappe-tafel:has(.mp-vorschau) { max-width: none; }

.mp-geraet {
  position: relative;
  /* **`content-box`**: `width` ist der Schirm, die Fassung kommt aussen dazu -
     so steht in der Regel die Zahl, um die es geht. */
  box-sizing: content-box;
  width: var(--mp-breite); height: var(--mp-hoehe);
  transform: scale(var(--mp-zoom)); transform-origin: top left;
  border: var(--mp-rand) solid var(--strong); border-radius: 2.6rem;
  background: var(--strong);
  padding: 0; overflow: hidden;
  box-shadow: 0 10px 30px rgb(0 0 0 / .18);
  /* Die Statusleiste steht oben, die Seite nimmt den Rest. */
  display: flex; flex-direction: column;
}

/**
 * **Die Statusleiste ist der Abstand, den die Kamera braucht.**
 *
 * Die Kerbe lag ueber dem Inhalt - also ueber der ersten Zeile der Mappe, und
 * im Rahmen sah die Seite kaputt aus, obwohl auf einem echten Telefon nichts
 * darunterliegt. Die Leiste schiebt sie hervor und ist zugleich das, was aus
 * dem Rahmen ein Telefon macht.
 *
 * Sie liegt **auf dem Bildschirm**, nicht auf der Fassung: Sie traegt das
 * Papier der Seite und ihre Schriftfarbe, die runde Ecke oben gehoert damit
 * ihr. Nur am Telefon - ein Schirm hat keine, und am Tablet braucht die Mappe
 * den Platz nicht.
 */
.mp-vorschau[data-geraet="telefon"] .mp-status {
  display: flex; align-items: center; justify-content: space-between;
  flex: none; height: 2.6rem; padding: 0 1.4rem;
  /**
   * **Schwarz wie die Leiste darunter.** Die Mappe traegt oben eine schwarze
   * Leiste; eine weisse Statuszeile darueber schnitt sie ab und sah aus wie
   * ein Streifen, den jemand vergessen hat. Zusammen sind es **ein** Band -
   * genau das, was ein Telefon zeigt, dessen App oben dunkel ist.
   *
   * Die Kerbe verschwindet damit im Grund, und das ist richtig: Sie ist
   * dieselbe Farbe wie der Rand, und auf einem echten Geraet sieht man sie
   * ueber einer dunklen App auch nicht.
   */
  background: var(--nav); color: var(--nav-ink);
  border-radius: 1.8rem 1.8rem 0 0;
  /* Ueber dem Papier, unter der Kerbe. */
  position: relative; z-index: 1;
}
.mp-status { display: none; }
.mp-status-uhr { font-size: .78rem; font-weight: 600; font-variant-numeric: tabular-nums; }
/* Die Zahl steht vor dem Zeichen, wie auf dem Geraet - und in derselben
   Groesse wie die Uhr gegenueber, damit die Leiste eine Zeile bleibt. */
.mp-status-prozent { font-size: .72rem; font-variant-numeric: tabular-nums; }
/* Die drei Zeichen stehen in einer Reihe und auf einer Grundlinie; ihre Hoehe
   ist die der Schrift daneben, damit die Leiste eine Zeile bleibt. */
.mp-status-zeichen { display: flex; align-items: center; gap: .3rem; }
.mp-status-zeichen svg { height: .62rem; width: auto; fill: currentColor; display: block; }
/* **Das WLAN-Zeichen steht etwas hoeher** (.72 statt .62 rem): Es sind drei
   Boegen und ein Punkt in einer Hoehe, in der die Balken daneben nur vier
   Rechtecke sind - bei gleicher Hoehe wird daraus Grau. Auf einem Telefon ist
   es aus demselben Grund das groesste der drei. */
.mp-status-zeichen .mp-wlan { height: .72rem; }
/* Die Kerbe: eine schwarze Insel oben, wie sie jedes Telefon seit Jahren hat.
   Sie liegt **ueber** dem Inhalt und nimmt ihm keinen Platz. */
/**
 * **Die Insel traegt eine graue Kante.** Auf der schwarzen Statusleiste ist
 * sie sonst unsichtbar - dieselbe Farbe auf derselben Farbe -, und damit
 * fehlte dem gezeichneten Telefon das Zeichen, an dem man es erkennt. Die
 * Kante ist leise: Sie soll die Form zeigen, nicht einen Rahmen.
 */
.mp-geraet::before {
  content: ""; position: absolute; z-index: 3; top: .5rem; left: 50%;
  transform: translateX(-50%);
  width: 7.5rem; height: 1.6rem; border-radius: 999px; background: var(--strong);
  border: 1px solid color-mix(in srgb, var(--nav-ink) 32%, transparent);
}
/* Der Strich unten - der Griff, mit dem man eine App verlaesst. */
.mp-geraet::after {
  content: ""; position: absolute; z-index: 2; bottom: .45rem; left: 50%;
  transform: translateX(-50%);
  width: 8rem; height: .25rem; border-radius: 999px;
  background: color-mix(in srgb, var(--paper) 55%, transparent);
}
.mp-geraet iframe {
  width: 100%; height: 100%; border: 0; display: block;
  border-radius: 1.8rem; background: var(--paper);
}
/* Mit Statusleiste gehoert die obere Rundung ihr - und die Seite nimmt, was
   von der Hoehe uebrig ist. */
.mp-vorschau[data-geraet="telefon"] .mp-geraet iframe {
  height: auto; flex: 1; min-height: 0; border-radius: 0 0 1.8rem 1.8rem;
}

@media (max-width: 30rem) {
  /* Auf dem Telefon selbst waere ein Telefon im Telefon albern - dann steht
     die Vorschau einfach so breit da, wie der Schirm ist. */
  .mp-vorschau { --mp-hoehe: 70vh; --mp-rand: 8px; }
  .mp-geraet { border-radius: 1.8rem; }
  .mp-geraet::before { width: 6rem; height: 1.2rem; }
}

/* **Der Satz unter einer Tabelle** - er erklaert sie, also steht er kleiner da
   als ihr Inhalt und mit Luft dazwischen. Ueber die ganze Breite und nicht in
   Lesebreite: Er gehoert zur Tabelle darueber, und die ist so breit wie die
   Flaeche. */
.tab-fussnote {
  margin: 1.2rem 0 0; max-width: none;
  font-size: .85rem; color: var(--soft);
}

/* Der Kasten „Ohne Ergebnis gesucht" stand hier einen Tag lang und ist am
   05.09.2026 wieder weggefallen: Die Spalte in der Tabelle sagt dasselbe, in
   derselben Zeile wie die Zahl daneben. `.such-leer` bleibt - das ist das Wort
   „immer" in genau dieser Spalte. */
.such-leer { color: var(--soft); font-size: .82rem; }
/**
 * **Eine gezählte Zahl in einer Tabelle** - dieselbe Klasse Angabe wie die
 * Entfernung in der Mappe: Was die Software rechnet, trägt ihre Schrift.
 * Anders als `.plan-pille` steht hier eine **Zahl** und kein Zustandswort,
 * also ohne Versalien und ohne Sperrung, und in der Textfarbe - sie ist der
 * Grund, aus dem jemand die Spalte liest.
 */
.zahl-pille {
  display: inline-block;
  padding: .25rem .75rem;
  border-radius: 999px; background: var(--shade);
  font-family: var(--mono); font-size: .68rem; color: var(--ink);
  white-space: nowrap;
}

/* **Woher sie kamen, aufgeklappt.** Der Chevron sitzt hinter dem Wort
   in derselben Zeile wie die Zahl; die Einzelheiten stehen eingerueckt darunter,
   damit sie als Unterzeile lesbar bleiben und nicht als neue Sorte. */
.herkunft-liste .dash-balken-kopf { display: flex; align-items: center; gap: .2rem; }
/* Das Wort steht ganz links, der Chevron gleich dahinter, die Zahl rechts -
   damit fluchten alle Woerter, auch die ohne Einzelheiten. */
.herkunft-liste .herkunft-wort { flex: none; }
.herkunft-liste .herkunft-zahl { margin-left: auto; }
.herkunft-liste .post-klapp { padding: 0; margin: 0; }
.herkunft-mehr {
  list-style: none; margin: .5rem 0 .2rem 1.4rem; padding: 0;
  font-size: .86rem; color: var(--soft);
}
.herkunft-mehr li {
  display: flex; gap: 1rem; justify-content: space-between;
  padding: .15rem 0;
}
.herkunft-mehr li span:first-child { overflow-wrap: anywhere; }
.herkunft-mehr li span:last-child { font-variant-numeric: tabular-nums; flex: none; }

/* **Die Marke ueber einer Liste** - „VON AUSSEN", „AUS DEM GUIDE", „EINTRAEGE
   UND VERANSTALTUNGEN". Dieselbe Typografie wie die Gruppen in der FAQ-Liste
   (`.ed-faqgruppe`): Es ist dieselbe Sache - eine Zwischenmarke in einer Liste,
   keine Ueberschrift eines Abschnitts. Zwei Groessen fuer dieselbe Rolle waeren
   zwei Rollen.

   Und deshalb steht sie hier neben der Liste, die sie beschriftet, statt als
   `h2` unter den Bereichstiteln: Ein `h1` sagt „das ist die Seite", diese Marke
   sagt „das ist die naechste Liste". */
.bk-listentitel {
  font-size: .85rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--soft); margin: 2rem 0 .4rem;
}
/* Die Fussnote direkt unter der Marke gehoert zu ihr - der Abstand darueber
   waere sonst doppelt so gross wie der zur Liste darunter. */
.bk-listentitel + .tab-fussnote { margin-top: 0; }
/* Eine Gruppe der Herkunftsliste. Der Abstand steht an der Marke, nicht hier -
   sonst addieren sich zwei. */
.herkunft-gruppe + .herkunft-gruppe { margin-top: .4rem; }

/* Die vier Schritte, mit denen Googles Zahlen hereinkommen. Eine Zahlenliste
   und keine Punkte: Es ist eine Reihenfolge, und die dritte ohne die zweite
   geht nicht. */
.google-schritte { margin: .8rem 0 0; padding-left: 1.4rem; max-width: var(--text); }
.google-schritte li { margin: .35rem 0; }

/* **Die drei Stufen auf der Anmeldeseite** (05.09.2026): dieselbe Leistungsliste
   wie auf der Angebotsseite, nur kuerzer - und mit Abstand nach oben, damit sie
   nicht wie ein Teil des Formulars aussieht. */

/* MEMBER OF - das Zeichen und der Schnipsel dazu (05.09.2026).

   Das Zeichen steht **gross** da: Es ist eine Marke, kein Symbol in einer
   Zeile, und der Wirt soll sehen, was er auf seine Seite setzt. Der Kasten
   darunter ist ein Textfeld und kein Kasten mit Code-Schrift - man liest ihn
   nicht, man kopiert ihn. */

/**
 * ===========================================================================
 * **DIE OFFENE AUSWAHL** - Radios, die wie Schalter aussehen  (06.09.2026)
 * ===========================================================================
 *
 * Fuer eine Frage mit wenigen Antworten, die alle auf den Bildschirm passen:
 * „Fuer welchen Eintrag?" Ein `select` versteckt dort alles ausser einer Zeile
 * hinter einem Klick - bei drei Zeilen ist das ein Handgriff zu viel.
 *
 * Darunter liegen **echte Radios** (`visually-hidden`), gestaltet wird das
 * Label darum herum. Dasselbe Muster wie der Primärbild-Stern im Editor: Die
 * Bedienung kommt vom Browser (Pfeiltasten, Gruppierung, Vorleseprogramm), das
 * Aussehen von uns.
 *
 * Eckig, wie alles hier - die Pillen der Gattungen sind die dokumentierte
 * Ausnahme, nicht die Regel.
 *
 * **Der gewaehlte Zustand ist die gefuellte Flaeche, und sonst nichts.** Nicht
 * nur ein Rahmen: Der unterscheidet sich zu wenig von dem der anderen. Und
 * **kein zweites Schriftgewicht** - eine gefuellte Flaeche ist bereits ein
 * Unterschied, der ohne Farbe trägt, also braucht es das Fett nicht als
 * Kruecke. Es war dazu die einzige Stelle, an der es stand: Schalter,
 * Gattungspillen, Zahlweise und Reiter fuellen nur. Dieselbe Frage in einem
 * Haus zweimal verschieden beantwortet ist eine Bedienung, die man zweimal
 * lernt - und es ist dieselbe Regel wie am aktiven Reiter, der sich durch
 * Strich und Farbe unterscheidet und nie durch Fettschrift.
 */
.wahlfeld { border: 0; padding: 0; margin: 0 0 1.2rem; }
.wahlfeld legend {
  padding: 0; margin: 0 0 .45rem;
  font-size: .9rem; color: var(--soft);
}
.wahlreihe { display: flex; flex-wrap: wrap; gap: .5rem; }
.wahl {
  display: inline-flex; align-items: center;
  border: 1px solid var(--line); padding: .5rem .85rem;
  cursor: pointer; line-height: 1.2;
}
.wahl:hover { border-color: var(--strong); }
.wahl:has(input:checked) {
  background: var(--accent); border-color: var(--accent); color: var(--paper);
}
/* Der Fokusring gehoert an das Label - das Radio darin ist unsichtbar. */
.wahl:has(input:focus-visible) { outline: 2px solid var(--strong); outline-offset: 2px; }
.wahl:has(input:disabled) { opacity: .45; cursor: default; }

/**
 * **More than one may be picked - then the field is a pill, and picked is
 * green with a tick.** A row of checkboxes looked exactly like a row of
 * radios, and "one of these" was the only reading it offered. So a `.wahl`
 * around a checkbox takes the form of the running tier (`.abo-aktiv`): round
 * at both ends, and once picked the state pair for "live" with the tick in
 * front. Radios keep the square field filled black - one of these; pills
 * are any of these.
 *
 * Round is the form of the part, not a round box: a pill is a thing that is
 * switched on and off, the same exception as the regulator and the fields
 * of the guest folder. 36 px high (`--regler-hoehe`), like every switch.
 *
 * The tick is the house's `check` from `ICON_PATHS` (`chrome.js`) as a mask,
 * stroke 2 like `.abo-aktiv svg`, so the path stands here a second time;
 * change one, change both. Only for `> input[type=checkbox]`: the rails and
 * the regulator restyle `.wahl` and carry radios.
 */
.wahl:has(> input[type=checkbox]) {
  border-radius: 999px; gap: .35rem;
  min-height: var(--regler-hoehe); padding: .3rem .95rem;
}
.wahl:has(> input[type=checkbox]:checked) {
  background: var(--state-live-bg); border-color: var(--state-live-bg);
  color: var(--state-live-ink); padding-left: .6rem;
}
.wahl:has(> input[type=checkbox]:checked):hover { border-color: var(--state-live-ink); }
.wahl:has(> input[type=checkbox]:checked)::before {
  content: ""; flex: none; width: 1rem; height: 1rem;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.4 9.2 6.6 12.4 13.6 5.4'/%3E%3C/svg%3E") center / 100% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.4 9.2 6.6 12.4 13.6 5.4'/%3E%3C/svg%3E") center / 100% no-repeat;
}

/**
 * **The theme of an event, picked on its sign** (editor, tab "Bilder").
 *
 * The same `.wahl` with its hidden radio - arrow keys, group announcement and
 * screen reader come from the browser - only standing upright: the placeholder
 * of the calendar row on top, exactly as the row draws it, the word below.
 * A fixed width so nine tiles form an even grid; the longest word
 * ("Kunst, Literatur & Bühne") breaks onto two lines instead of widening its
 * tile. Checked is the filled area of every choice in the house; the
 * placeholder keeps its own ground, so the sign stays readable on it.
 */
.thema-wahl-reihe { gap: .5rem; }
.thema-wahl-feld {
  flex-direction: column; justify-content: flex-start; gap: .45rem;
  width: 6.5rem; padding: .6rem .4rem; text-align: center;
}
.thema-wahl-wort { font-size: .8rem; line-height: 1.25; }

/**
 * ===========================================================================
 * **Der Regler** - dieselbe Wahlreihe, gebaut fuer genau zwei Moeglichkeiten
 * ===========================================================================
 *
 * Zwei Pillen nebeneinander sind zwei Knoepfe: Man liest sie als „hier kann
 * man zweierlei druecken". Ein Regler ist **ein** Bedienelement mit zwei
 * Enden - er sagt, dass es einen Zustand gibt und dass er kippt. Genau das ist
 * gemeint, wo eine Flaeche ihren Grund wechselt oder eine Ansicht ihre Seite.
 *
 * **Die Enden sind rund - die achte dokumentierte Ausnahme** von
 * `border-radius: 0` (08.09.2026). Eine Fassung mit Ecken stand einen Tag lang
 * hier, mit dem Argument „die Bewegung macht den Regler, nicht die Rundung".
 * Der bessere Grund geht andersherum: **Ein Regler ist eine Bahn, und eine Bahn
 * hat Enden, keine Ecken.** Eine Ecke am Ende einer Fahrstrecke liest sich als
 * Anschlag; rund liest sie sich als das, was sie ist. Dieselbe Art von Grund
 * wie beim Play/Pause-Knopf: die eine Form, die jeder Mensch fuer diese
 * Handlung kennt. „Weicher" allein waere weiter kein Grund.
 *
 * **Die Schrift ist kleiner als im Fliesstext** (.85rem): Ein Regler ist eine
 * Einstellung neben dem Inhalt, keine Aussage darin.
 *
 * **Darunter liegen dieselben zwei Radios** wie in jeder Wahlreihe, unsichtbar.
 * Pfeiltasten, Gruppenansage und Vorleseprogramm kommen damit vom Browser; der
 * Schieber ist Anzeige, nicht Bedienung. Wer eine dritte Moeglichkeit braucht,
 * nimmt die gewoehnliche Wahlreihe - ein Regler mit drei Enden ist keiner.
 * =========================================================================== */
.wahlreihe.regler {
  position: relative; display: inline-grid; grid-auto-flow: column;
  grid-auto-columns: 1fr; gap: 0;
  border: 1px solid var(--line); border-radius: 999px;
}
/* Die Spur: eine Haelfte breit, faehrt beim Umschalten hinueber - zwei Pixel
   innerhalb des Rahmens, damit die runde Kante rundherum stehen bleibt. */
.wahlreihe.regler::before {
  content: ""; position: absolute; z-index: 0; top: 2px; bottom: 2px; left: 2px;
  width: calc(50% - 3px); border-radius: 999px;
  background: var(--accent); transition: transform .18s ease;
}
.wahlreihe.regler:has(.wahl:last-child input:checked)::before {
  transform: translateX(calc(100% + 2px));
}
@media (prefers-reduced-motion: reduce) {
  .wahlreihe.regler::before { transition: none; }
}
/**
 * **Schalter und Regler tragen dasselbe Mass** - dieselbe Schriftgroesse und
 * dieselbe Hoehe (`.32rem` senkrecht, `.8rem` Schrift, wie `.wahlreihe.schalter
 * .wahl`). In der Terminliste stehen sie **nebeneinander** in einer Zeile; zwei
 * Bauteile derselben Familie, die verschieden hoch sind, lesen sich dort als
 * zwei Rangstufen - und eine Rangfolge gibt es zwischen ihnen nicht, beide
 * schneiden quer zur Zeitachse.
 *
 * **Waagerecht darf er weiter atmen** (`1rem` statt `.7rem`): Der Schalter
 * stoesst Feld an Feld und braucht die Kante als Trennung, der Regler ist eine
 * Pille mit einer fahrenden Spur darin. Gleich ist, was man vergleicht -
 * Hoehe und Schrift -, nicht jede Zahl.
 */
.wahlreihe.regler .wahl {
  position: relative; z-index: 1; justify-content: center; border: 0;
  padding: .32rem 1rem; font-size: .8rem; transition: color .18s ease;
}
.wahlreihe.regler .wahl:hover { border-color: transparent; }
/* Der gewaehlte Zustand ist die Spur darunter - das Label traegt nur die
   Schrift. Ohne dieses Zuruecknehmen laege ein zweiter schwarzer Kasten auf
   der Spur, und beim Fahren saehe man die Kante. */
.wahlreihe.regler .wahl:has(input:checked) { background: none; color: var(--paper); }
/* Der Ring gehoert um das ganze Bauteil: Getroffen wird ein Regler, nicht eine
   seiner Haelften. */
.wahlreihe.regler:has(input:focus-visible) {
  outline: 2px solid var(--strong); outline-offset: 2px;
}
.wahlreihe.regler .wahl:has(input:focus-visible) { outline: none; }

/**
 * ===========================================================================
 * **Der Schalter** - dieselbe Wahlreihe, gebaut fuer mehr als zwei
 * ===========================================================================
 *
 * Der Regler darueber hat genau zwei Enden; „ein Regler mit drei Enden ist
 * keiner". Fuer die **zwei Sprachen** einer Seite braucht es trotzdem
 * dasselbe: **ein** Bedienelement mit mehreren Feldern und nicht fuenf
 * Knoepfe nebeneinander. Fuenf Pillen mit Abstand lesen sich als fuenf
 * Handlungen; ein Schalter liest sich als **eine** Frage mit fuenf Antworten -
 * und genau eine davon gilt.
 *
 * **Die Enden sind rund - dieselbe Ausnahme wie beim Regler** (die achte, sie
 * zaehlt fuer beide): Ein Schalter ist eine Bahn mit Feldern darauf, und eine
 * Bahn hat Enden, keine Ecken. Innen bleibt alles eckig; getrennt wird mit
 * einer Linie, nicht mit Luft.
 *
 * **Kleiner als der Fliesstext** (.8rem): Er ist eine Einstellung neben dem
 * Inhalt, keine Aussage darin - dasselbe Argument wie beim Regler, eine Stufe
 * knapper, weil hier fuenf Felder nebeneinander stehen.
 *
 * `overflow: hidden` ist der Grund, warum das gewaehlte **Endfeld** aussen rund
 * endet: Seine Flaeche wird von der runden Kante des Traegers beschnitten. Ohne
 * das saesse ein eckiger Kasten in einer runden Bahn.
 * =========================================================================== */
.wahlreihe.schalter {
  display: inline-flex; flex-wrap: nowrap; gap: 0;
  border: 1px solid var(--line); border-radius: 999px; overflow: hidden;
  /**
   * **Er ist so breit wie seine Felder, nicht wie die Spalte.** In einem Raster
   * (`.ed-block` ist eines) wird ein Kind gestreckt, und `inline-flex` allein
   * verhindert das nicht: Die Zeile waere ein Schalter mit einer handbreit
   * leerem Rand rechts - eine Bahn, die ins Nichts weiterlaeuft.
   */
  justify-self: start; width: fit-content; max-width: 100%;
}
.wahlreihe.schalter .wahl {
  border: 0; border-left: 1px solid var(--line); border-radius: 0;
  justify-content: center; padding: .32rem .7rem;
  font-size: .8rem; white-space: nowrap;
}
.wahlreihe.schalter .wahl:first-child { border-left: 0; }
.wahlreihe.schalter .wahl:hover { border-color: var(--line); background: var(--shade); }
.wahlreihe.schalter .wahl:first-child:hover { border-left-color: transparent; }
/* Gewaehlt ist die **Flaeche**, nicht der Rahmen - der gehoert dem Schalter. */
.wahlreihe.schalter .wahl:has(input:checked) {
  background: var(--strong); border-color: var(--line); color: var(--paper);
}
/* Der Ring gehoert um das ganze Bauteil: Getroffen wird ein Schalter, nicht
   eines seiner Felder. */
.wahlreihe.schalter:has(input:focus-visible) {
  outline: 2px solid var(--strong); outline-offset: 2px;
}
.wahlreihe.schalter .wahl:has(input:focus-visible) { outline: none; }
/* Die Zahl ist der Grund, warum man hier klickt - leiser, aber nicht stumm. */
.wahlreihe.schalter .reiter-zahl { margin-left: .35rem; opacity: .7; font-size: .95em; }

.mof { max-width: 56rem; margin-top: 1rem; }
/* Zwei Fassungen nebeneinander, jede auf **ihrem** Grund: Erst dann sieht man,
   welche man braucht - ein weisses Zeichen auf weissem Papier ist unsichtbar,
   und genau das ist die Auskunft. */
/* A card like the plan cards of the subscription page - rounded
   (`--card-radius`) and on paper: the version is a card one picks up, not a
   box of the layout. */
.mof-fassung {
  border: 1px solid var(--line); border-radius: var(--card-radius); padding: 1rem 1.1rem;
  background: var(--paper);
}
.mof-kopf {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .6rem 1rem; margin-bottom: .9rem;
}
.mof-kopf h3 { margin: 0; font-size: 1rem; }
.mof-kopf .wahlreihe { margin: 0; }
.mof-kopf .wahl span { display: inline-flex; align-items: center; gap: .35rem; }
.mof-grund-zeichen { width: .85rem; height: .85rem; flex: none; }
/* Only the chosen version stands - the switch decides, no script. */
.mof-fassung:has(input[name="mof-grund"][value="hell"]:checked) .mof-teil[data-grund="dunkel"],
.mof-fassung:has(input[name="mof-grund"][value="dunkel"]:checked) .mof-teil[data-grund="hell"] {
  display: none;
}
/* The whole row: the sign on its ground on the left, the snippet beside it. */
@media (min-width: 48rem) {
  .mof-teil { display: grid; grid-template-columns: 16rem 1fr; gap: 1.2rem; align-items: start; }
  .mof-teil .mof-buehne { margin-bottom: 0; min-height: 10.5rem; }
  .mof-teil .feld { margin: 0; }
}
.mof-buehne {
  display: flex; align-items: center; justify-content: center;
  padding: 1.2rem; margin-bottom: .9rem;
}
.mof-buehne[data-grund="hell"] { background: var(--paper); border: 1px solid var(--line); }
.mof-buehne[data-grund="dunkel"] { background: var(--nav); }
.mof-buehne img { width: 160px; height: auto; }
.mof-code-kopf { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.mof .mof-code { font-size: .74rem; line-height: 1.45; }
.mof textarea { font-family: var(--mono); font-size: .82rem; }
.mof code {
  font-family: var(--mono); font-size: .9em;
  background: var(--shade); padding: 0 .25rem;
}
@media (max-width: 40rem) {
  .mof-reihe { flex-direction: column; gap: .8rem; }
}

/* ---------------------------------------------------------------------------
   AUS EINER ZEILE WIRD EINE KARTE  -  `.tab-karten`
   ---------------------------------------------------------------------------

   **Die Kartenform ist eine Klasse und kein Name einer Seite.** Sie hing an
   `[data-art="anspruch"]` und damit am Substantiv einer einzigen Flaeche
   („Mein Eintrag"); inzwischen tragen sie drei - die beanspruchten Eintraege,
   die Quellenliste und die Pruefliste. Drei Abschriften desselben Blocks waeren
   drei Stellen, an denen ein Eingriff fehlt.

   Der Anlass war und bleibt derselbe:

   **Der Kunde sitzt nicht am Schreibtisch.** Ein Gastgeber pflegt seinen
   Eintrag zwischen zwei Anreisen, mit einer Hand, auf einem Telefon. Alles, was
   ihn dort aufhaelt - eine Tabelle, die seitwaerts rollt, ein Feld, in das der
   Browser hineinzoomt, ein Knopf neben einem Knopf - ist eine Huerde vor einer
   Sache, die er ohnehin ungern macht.

   Drei Eingriffe, mehr braucht es nicht:

   1. **Aus jeder Zeile wird eine Karte.** Eine Tabelle mit drei Spalten ist auf
      375 px keine Tabelle mehr. Die Kopfzeile faellt weg und steht als Wort vor
      dem Wert (`data-spalte`) - dieselbe Auskunft, nur untereinander.
   2. **Die Formulare stehen ueber die ganze Breite**, und die Knoepfe auch:
      Ein Knopf, den man mit dem Daumen trifft, ist eine Zeile hoch.
   3. **Kein Hineinzoomen.** iOS vergroessert jedes Feld unter 16 px beim
      Antippen und schiebt danach die halbe Seite aus dem Bild. 1 rem ist genau
      die Grenze. */
@media (max-width: 46rem) {
  .bestand-tabelle.tab-karten { display: block; font-size: 1rem; }
  .bestand-tabelle.tab-karten thead { display: none; }
  .bestand-tabelle.tab-karten tbody,
  .bestand-tabelle.tab-karten tr { display: block; }
  .bestand-tabelle.tab-karten tr {
    border: 1px solid var(--line); padding: .9rem 1rem; margin-bottom: .8rem;
  }
  /**
   * **Die Werte stehen links, nicht verteilt** (05.09.2026).
   *
   * Hier stand `space-between`: Wort links, Zahl irgendwo, Zusatz am rechten
   * Rand - und weil „Bilder" und „Bewertungen" verschieden lang sind, stand
   * die Zahl in jeder Zeile woanders. Drei Werte, drei Fluchtlinien, und der
   * Blick musste sie einzeln suchen.
   *
   * Jetzt bekommt das Wort eine **feste Spalte** und alles danach schliesst
   * links daran an. Die Zahlen stehen damit untereinander - genau das, was
   * eine Tabelle tut, nur ohne Tabelle.
   */
  .bestand-tabelle.tab-karten td {
    display: flex; align-items: baseline; justify-content: flex-start;
    gap: .5rem; border: 0; padding: .3rem 0;
  }
  /* Der Name traegt Kurve, Pille und Ort - er bleibt ein Block. */
  .bestand-tabelle.tab-karten td.tab-name { display: block; padding: 0 0 .6rem; }
  .bestand-tabelle.tab-karten td[data-spalte]::before {
    content: attr(data-spalte); color: var(--soft); font-size: .88rem;
    /* So breit wie das laengste Wort („Bewertungen") und keinen Deut mehr:
       Was hier an Breite steht, fehlt der Zahl daneben. */
    flex: none; width: 7.5rem;
  }
  /* Der Zusatz („1 online") rutscht neben die Zahl statt darunter. Der Abstand
     kommt aus dem `gap` der Zeile - ein eigener Rand daneben waere derselbe
     Zwischenraum zweimal gesetzt. */
  .bestand-tabelle.tab-karten td[data-spalte] .tab-unten {
    display: inline; margin-left: 0;
  }
  /**
   * **„Entfernen" war eine 20 px flache Flaeche ueber die volle Breite, .6 rem
   * unter dem schwarzen Speichern-Knopf** (behoben am 07.09.2026). `stretch`
   * zog auch den Verweis auf die ganze Zeile, und `.wie-link` hat `padding: 0`
   * - der klassische Daumen-Fehlgriff, und er kostete einen Satz, den der Wirt
   * neu schreiben musste. Jetzt linksbuendig statt gedehnt, 1,4 rem Abstand
   * statt .6, und eine Trefferflaeche von 44 px.
   */
  .vorteil-knoepfe { flex-direction: column; align-items: flex-start; gap: 1.4rem; }
  .vorteil-knoepfe .action { width: 100%; }
  .vorteil-knoepfe .ed-vorteilweg {
    margin-left: 0; min-height: 44px; display: flex; align-items: center;
  }
  /* 1 rem ist die Grenze, unter der iOS beim Antippen hineinzoomt. */
  input[type=text], input[type=search], input[type=email], input[type=url],
  input[type=tel], input[type=number], input[type=password], input[type=date],
  input[type=time], select, textarea { font-size: max(1rem, .95em); }
}

/* ---------------------------------------------------------------------------
   The perks - the one section of an entry page the business writes itself.
   ---------------------------------------------------------------------------

   A section like every other on the page (its heading, one sentence on how to
   redeem), and below it the vouchers. No `border-radius` - corners are the
   brand (styleguide). */
.vorteil { max-width: var(--text); margin: 0 auto 2.2rem; text-align: left; }
.vorteil-titel { margin-bottom: .35rem; }
.vorteil-hinweis { margin: 0 0 1rem; color: var(--soft); font-size: .95rem; }
.perk-icon { width: 1.15rem; height: 1.15rem; flex: none; margin-top: .18rem; }
/* In the choice row of the editor the sign sits in the line, without the top
   margin it has in front of a sentence. */
.vorteil-zeichen .wahl span { display: inline-flex; align-items: center; gap: .35rem; }
/* The sign of a perk is chosen on pills - round, like the value it sets. */
.vorteil-zeichen .wahl { border-radius: 999px; }
.vt-frist-satz { margin: 0 0 .6rem; }
.vorteil-zeichen .perk-icon { margin-top: 0; width: 1rem; height: 1rem; }

/**
 * **The voucher** (`BFPChrome.vorteilKarte`) - one form on the entry page, in
 * the guest folder and in the editor's preview.
 *
 * Flat, on paper, a hairline around: a card of the house. What makes it a
 * voucher is the **stub** - a black square with the sign of the kind in
 * white. It grows with the voucher and has a floor, so a one-line perk is no
 * crumb.
 */
.gutscheine { list-style: none; margin: 0; padding: 0; display: grid; gap: .75rem; }
/* **The stub is a square, and the row is as high as it.** Title plus detail
   fit into 3.75 rem (60 px): the paddings and line heights below are sized to
   that, so the usual voucher is exactly one square high and the sign sits in
   its centre. A voucher that carries a code or a long title grows; then the
   stub grows with it and the sign stays centred. */
.gutschein {
  /* Plus the two hairlines - the square is the stub, not the border box. */
  display: flex; min-height: calc(3.75rem + 2px);
  border: 1px solid var(--line); background: var(--paper);
  /* A light radius - the house measure for a small picture (`--thumb-radius`,
     4 px), because a voucher is a thing one holds, not a box of the layout.
     `overflow: hidden` lets the stub follow the corners. */
  border-radius: var(--thumb-radius); overflow: hidden;
}
.gutschein-abriss {
  flex: none; width: 3.75rem; display: flex; justify-content: center; align-items: center;
  /* Black with a white sign - the ground of the header and of the pins of the
     house (`--nav`), so it turns with it in dark mode like the header does. */
  background: var(--nav); color: var(--nav-ink);
}
.gutschein-zeichen { width: 1.4rem; height: 1.4rem; }
.gutschein-koerper {
  flex: 1; min-width: 0; padding: .55rem .9rem;
  display: flex; flex-direction: column; justify-content: center;
}
.gutschein-koerper p { margin: 0; }
.gutschein-titel {
  font-size: 1.02rem; line-height: 1.25; font-weight: 600;
  hyphens: auto; overflow-wrap: break-word;
}
.gutschein-dazu { margin-top: .12rem !important; font-size: .88rem; line-height: 1.35; color: var(--soft); }
.gutschein-fuss {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: .4rem .8rem; margin-top: .45rem !important;
}
/* The code is typed off or shown at the counter: monospace, large, a solid
   edge, and it copies on tap. */
.gutschein-code {
  /* Round at both ends - a pill, like every classifying value of the house -
     and a step smaller: 36 px, the height of every control (`--regler-hoehe`). */
  display: inline-flex; align-items: center; gap: .4rem; min-height: var(--regler-hoehe); padding: 0 .8rem;
  font-family: var(--mono); font-size: .82rem; font-weight: 700; letter-spacing: .06em;
  color: var(--ink); background: var(--paper); border: 1px solid var(--strong); border-radius: 999px;
  cursor: copy;
}
.gutschein-code .nav-icon, .gutschein-code svg { width: .8rem; height: .8rem; color: var(--soft); }
.gutschein-code:hover { background: var(--shade); }
.gutschein-code:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/**
 * **The validity stands as a pill above the name** - a date is a system value,
 * and the house carries those in monospace on a quiet ground
 * (`.terminzeile-ort`, `.mp-km`, `.zahl-pille`). The paragraph is the carrier,
 * the pill its `span`: as wide as the date, not as wide as the card.
 */
/**
 * **With room, the code stands at the right, centred on the height** - text
 * left, the thing one taps right, the way a voucher is read: what you get,
 * then the key to it. Asked of the **voucher's** width, not the window's: the
 * same card stands in a wide column on the entry page and in a narrow one in
 * the guest folder. Below 32 rem it stays under the text, where a long title
 * still has the whole line.
 */
.gutschein { container: gutschein / inline-size; }
@container gutschein (min-width: 32rem) {
  .gutschein-koerper:has(.gutschein-fuss) {
    display: grid; grid-template-columns: minmax(0, 1fr) auto;
    column-gap: 1.2rem; align-content: center;
  }
  .gutschein-koerper > p:not(.gutschein-fuss) { grid-column: 1; }
  .gutschein-koerper > .gutschein-fuss {
    grid-column: 2; grid-row: 1 / span 3; align-self: center; margin-top: 0 !important;
  }
}
.gutschein-frist { margin: 0 0 .25rem !important; }
.gutschein-frist span {
  display: inline-block;
  padding: .25rem .75rem; border-radius: 999px; background: var(--shade);
  font-family: var(--mono); font-size: .68rem; color: var(--soft);
  white-space: nowrap;
}
/**
 * **The perks in the backend** (`vorteileTafel` in `editor.js`) - each voucher
 * as the guest sees it, the three signs beside it at the top right, the state
 * under it when it is not out there. A voucher that is not on the page is
 * dimmed: word and form, not colour alone.
 */
.vt-liste { list-style: none; margin: 0 0 .4rem; padding: 0; display: grid; gap: 1rem; }
/* The three signs sit on the voucher, at the top right; the body keeps room
   for them, so a long title does not run underneath. */
.vt-reihe { position: relative; display: grid; gap: .35rem; }
.vt-karte .gutschein-koerper { padding-right: 7.5rem; }
/* The signs are the corner of a tile (`.qr-tun`): the same squares, the red
   bin first, the switch last. The voucher is paper and not grey, so pointing
   shows the quiet fill of the house instead of the white of a tile. */
.vt-knoepfe.qr-tun { top: .4rem; right: .4rem; z-index: 1; } /* above the dimmed voucher, as on a tile */
.vt-knoepfe .tab-zeichen + .tab-zeichen { margin-left: 0; }
.vt-knoepfe .tab-zeichen:hover, .vt-knoepfe .tab-zeichen:focus-visible,
.vt-knoepfe .tab-weg:hover, .vt-knoepfe .tab-weg:focus-visible {
  background: var(--shade); border-radius: 4px;
}
.vt-zustand { margin: 0; font-size: .85rem; color: var(--soft); }
.vt-still .vt-karte { opacity: .55; }
/* The layer: the live voucher on top, the form below, the buttons at its foot. */
.vt-vorschau { margin: 0 0 1rem; }
.vt-vorschau-leer .gutschein-titel { color: var(--soft); font-weight: 400; }
.vt-form { display: grid; gap: .9rem; margin-top: 1rem; }
.vt-form .feld { margin: 0; }
.vt-fuss {
  position: sticky; bottom: 0; margin: .4rem 0 0; padding: .8rem 0;
  background: var(--paper); border-top: 1px solid var(--line);
}
@media (pointer: coarse) {
  .vt-vorschau { position: sticky; top: 0; z-index: 1; background: var(--paper); padding-bottom: .5rem; }
}
@media (max-width: 22rem) {
  .gutschein-abriss { width: 3.25rem; }
  .gutschein { min-height: calc(3.25rem + 2px); }
}

/* ---------------------------------------------------------------------------
   Das Video - ueber der Galerie.
   ---------------------------------------------------------------------------

   **Der Behaelter haelt das Verhaeltnis, nicht der Rahmen.** Ein `<iframe>` von
   YouTube kommt mit festen Pixelmassen; auf dem Telefon ragt es damit aus der
   Seite und schiebt den ganzen Text quer - die eine Sache, die eine Einbettung
   von aussen zuverlaessig kaputt macht. Deshalb `aspect-ratio` auf dem Kasten
   und 100 Prozent auf dem Rahmen: Die Hoehe folgt der Breite, egal was das
   Fremdstueck von sich behauptet.

   Kein `border-radius` - Ecken sind Marke (Styleguide).

   **Der Rahmen und die Zeile darunter gehoeren zusammen** - deshalb eine
   `figure` um beides, und sie traegt den Aussenabstand: Zwischen Video und
   Herkunftszeile darf keiner stehen, unter der Zeile schon.

   Die Zeile kann nicht **in** `.video` stehen - der Kasten hat ein
   Seitenverhaeltnis und `overflow: hidden`, sie waere abgeschnitten. */
.videoblock { margin: 0 0 1.2rem; }
.video {
  aspect-ratio: 16 / 9; width: 100%;
  background: var(--videogrund); overflow: hidden;
}
.video iframe { display: block; width: 100%; height: 100%; border: 0; }
.video-quelle {
  margin: .4rem 0 0; font-size: .85rem; color: var(--soft);
}
/* **Keine eigene Farbe fuer den Verweis.** Der Anbietername ist ein Verweis im
   Fliesstext und sieht aus wie jeder andere (`--strong`, unterstrichen); den
   Pfeil nach draussen setzt `chrome.js`. Eine zweite Farbe hier waere ein
   zweiter Verweistyp fuer eine Zeile. */

/* **The main picture on top, the rest below** - the form of the phone, on
   every width. With the big picture on the left it stood in a cell of 2 : 3
   of the frame, and a landscape photo lost half of itself.

   **Der Rahmen hat kein eigenes Verhaeltnis mehr** (28.09.2026). Er hatte
   `aspect-ratio: 1/1` und Zeilen aus `fr`, und damit stand die Form der Kachel
   vor dem Bild: Jede Zelle war 3:2, auch die mit einem Hochformat darin, und
   `cover` nahm dem Bild die halbe Hoehe. Jetzt gibt die Kachel ihr Verhaeltnis
   vor (`.photo`, `.photo-hoch`), und die Zeile richtet sich danach - deshalb
   `auto` und nicht `minmax(0, …)`: Eine Zeile, die sich nach ihrer hoechsten
   Kachel streckt, ist hier keine Panne mehr, sondern die Absicht. */
.gallery {
  display: grid; gap: .5rem; margin: 0 0 1.2rem;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto auto;
}
/* `width: 100%` ist nicht ueberfluessig: Ein Bild, das noch nicht geladen ist,
   hat ohne Seitenverhaeltnis keine Breite - und die Kachel fiel damit auf null
   zusammen, bis das Foto ankam. Mit der Angabe steht das Raster sofort.

   **Die Kachel hat zwei Formen, nicht eine**: 3:2 fuer ein Querformat, 2:3 fuer
   ein Hochformat. Welche gilt, sagt `item.js` mit `photo-hoch` an der Figur -
   das Stylesheet kann die Masse des Bildes nicht lesen. */
.gallery .photo { margin: 0; min-width: 0; min-height: 0; width: 100%; height: auto; }
/**
 * **Das Verhaeltnis steht auf einem Platzhalter, nicht auf der Kachel**
 * (28.09.2026).
 *
 * Auf der Kachel selbst hat es die Zeile zerrissen: `aspect-ratio` rechnet die
 * Hoehe aus der Breite, und eine so errechnete Hoehe schlaegt
 * `align-items: stretch`. Stand ein Querformat neben einem Hochformat, blieb
 * es bei 477 px, waehrend die Zeile 1074 px hoch war - eine Luecke, kein
 * Zuschnitt. Gemessen an der Ravennaschlucht.
 *
 * Als `::before` gibt das Verhaeltnis der Zeile ihre Hoehe und laesst die
 * Kachel trotzdem `auto` - also streckbar. Die flachere Kachel waechst damit
 * auf die Zeilenhoehe, und `cover` beschneidet sie nach `focus`, wie ueberall.
 * Der Griff liegt darueber (`inset: 0`), damit der Platzhalter ihn nicht nach
 * unten schiebt; der Bildnachweis liegt ohnehin absolut.
 */
.gallery .photo::before { content: ""; display: block; aspect-ratio: 3 / 2; }
.gallery .photo-hoch::before { aspect-ratio: 2 / 3; }
.gallery .photo-zoom { position: absolute; inset: 0; }
.gallery .photo:first-child { grid-column: 1 / -1; grid-row: 1; }
/* Die Bilder fuellen ihre Kachel - beschnitten wird nach `focus`, wie ueberall. */
.gallery .photo img { width: 100%; height: 100%; aspect-ratio: auto; }

/* ---------------------------------------------------------------------------
   **DIE ZAHL MACHT DAS RASTER**

   Jede Kachel bleibt 3:2 - deshalb hat jeder Satz sein eigenes
   Seitenverhaeltnis, statt die Bilder in ein festes zu quetschen. Gerechnet
   auf die Breite `w`:

     zwei    Hoehe w/3          nebeneinander            3 : 1
     drei    Hoehe w/1.5 + w/3  eins breit, zwei darunter  1 : 1
     vier    Hoehe 2 · w/3      zwei mal zwei              3 : 2
     ab fuenf: wie drei - eins breit, zwei darunter, der Rest im Lichtkasten

   **Ab fuenf bleibt es bei drei sichtbaren.** Ein Raster mit fuenf Kacheln hat
   eine Luecke oder eine Reihe zu wenig, und beides liest sich als Fehler.
   Drei und ein Hinweis „+2" sagen dagegen genau das, was gilt. */
.gallery[data-count="2"] {
  grid-template-columns: 1fr 1fr; grid-template-rows: auto;
}
.gallery[data-count="2"] .photo:first-child { grid-column: 1; grid-row: 1; }

/* **Ein Satz aus einem Bild ist kein Raster.** Es steht ueber die ganze Breite
   und behaelt seine Hoehe - `aspect-ratio: 9/4` der Grundform waere ein
   Streifen, und eine Zeile hoch waere es ohnehin. Der Behaelter ist trotzdem
   eine `.gallery`: Er ist der **Satz**, und daran haengt der Lichtkasten. */
.gallery[data-count="1"] { display: block; aspect-ratio: auto; }
.gallery[data-count="1"] .photo { height: auto; }

/* Drei (und ab fuenf): die Grundform oben - eins ueber die Breite, zwei darunter. */

/* Vier: zwei mal zwei. Kein grosses Bild - bei vier gibt es keine Rangfolge,
   die das Raster ausdruecken koennte, und eine erfundene waere eine Behauptung
   ueber die Bilder. */
.gallery[data-count="4"] {
  grid-template-columns: 1fr 1fr; grid-template-rows: auto auto;
}
.gallery[data-count="4"] .photo:first-child { grid-column: 1; grid-row: 1; }

/* Die Bilder, die erst in der Galerie erscheinen: im Dokument, nicht im Raster.
   `display: none` waere fuer manche Vorleseprogramme nicht vorhanden. */
.gallery-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* Der Griff um das Bild ist ein Knopf - und darf nach nichts aussehen: kein
   Rahmen, kein Grund, kein Innenabstand. Sichtbar ist er nur beim Tasten. */
.photo-zoom {
  display: block; position: relative; width: 100%; height: 100%;
  padding: 0; border: 0; background: none; cursor: zoom-in; color: inherit;
}
.photo-zoom:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* **Im Text gibt das Bild die Hoehe vor, nicht die Zelle.** In einer Galerie
   fuellt der Griff seine Rasterzelle (`height: 100%`); ein einzelnes Bild im
   Text, eines neben einem Absatz und ein Kopfbild stehen in keiner - dort
   waeren 100% die Hoehe des Elternteils, und die kommt vom Bild. */
.text-bild .photo-zoom,
.text-bild-neben .photo-zoom,
.hero .photo-zoom { height: auto; }

/* „alle Bilder anzeigen" liegt auf der letzten Kachel.

   **Die Kachel ist immer abgedunkelt, nicht erst beim Zeigen** (03.09.2026).
   Vorher lag hier ein Verlauf von unten - unten .55, oben .25 - damit das Bild
   moeglichst wenig verdeckt wird. Der Preis war, dass die Schrift oben auf
   einem hellen Foto kaum stand und die Kachel nicht als Schalter zu erkennen
   war: Sie sah aus wie die beiden daneben, nur mit Text darauf.

   Eine gleichmaessige Flaeche sagt dagegen auf den ersten Blick, dass hier
   etwas anderes passiert als beim Klick auf ein Bild. Das Foto bleibt darunter
   erkennbar - abgedunkelt heisst nicht verdeckt.

   Die Werte stehen fest und nicht als Token: Die Flaeche liegt auf einem Foto
   und muss in beiden Modi dunkel bleiben - dieselbe Ausnahme wie beim
   Bildnachweis, siehe Kopf dieser Datei. Ein Grund, der im Dunkelmodus
   mitzieht, waere auf einem naechtlichen Foto keiner. */
.photo-more {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: .6rem; text-align: center;
  color: #fff; font-weight: 700; font-size: clamp(.8rem, 1.6vw, 1rem); line-height: 1.25;
  background: rgba(0, 0, 0, .55);
  transition: background .18s ease;
}
/* Beim Zeigen etwas tiefer - eine Rueckmeldung, keine zweite Gestaltung. */
.photo-zoom:hover .photo-more,
.photo-zoom:focus-visible .photo-more { background: rgba(0, 0, 0, .68); }
@media (prefers-reduced-motion: reduce) {
  .photo-more { transition: none; }
}

/* Untereinander: das grosse Bild ueber die ganze Breite, die zwei kleinen
   darunter nebeneinander. Hier darf das Raster wieder wachsen - es gibt keine
   Kachel, die zwei Zeilen ueberspannt, also auch keinen Ring. */
@media (max-width: 45.99rem) {
  /* `[data-count]` und nicht eine Aufzaehlung der Zahlen: Die Regeln oben sind
     spezifischer als `.gallery` allein und wuerden hier sonst gewinnen - und
     die naechste Zahl waere die, die man vergisst. */
  .gallery, .gallery[data-count] {
    grid-template-columns: 1fr 1fr; grid-template-rows: none; aspect-ratio: auto;
  }
  .gallery .photo { height: auto; }
  .gallery .photo:first-child,
  .gallery[data-count] .photo:first-child { grid-column: 1 / -1; grid-row: auto; }
  /* **Zwei bleiben zwei** (10.09.2026): „das große zuerst, der Rest darunter"
     braucht einen Rest - bei zwei Bildern gibt es keinen, und das erste über
     die ganze Breite mit dem zweiten halb daneben liest sich als Fehler im
     Satz. Zwei nebeneinander sind auf dem Telefon schmal, aber ein Paar. */
  .gallery[data-count="2"] .photo:first-child { grid-column: auto; }
}

/* ---------------------------------------------------------------------------
   Die Galerie ueber der Seite.
   ---------------------------------------------------------------------------

   Ein `<dialog>`: Fluchttaste, Fokus im Kasten und die stillgelegte Seite
   dahinter bringt der Browser mit. Der Grund ist schwarz, weil daneben nichts
   sein soll - nur das Bild und wem es gehoert. */
/* **Genau der Ausschnitt, nichts daneben.** `100vw` waere falsch: Es zaehlt die
   Rollleiste mit, der Dialog wird breiter als das Fenster, und rechts fehlten
   der Pfeil und das X. `inset: 0` gegen die eigenen Hoechstmasse des Browsers
   ist die genaue Angabe - fuellen, nicht rechnen. */
.lightbox {
  position: fixed; inset: 0; width: auto; height: auto;
  max-width: none; max-height: none; border: 0; padding: 0; margin: 0;
  /* Weisser Grund, schwarze Quadrate - dieselbe Ordnung wie auf der Seite. Ein
     dunkler Leuchtkasten waere eine zweite Welt, und der Zurueckknopf, den man
     zwei Zeilen darueber gesehen hat, waere darin ein anderer Knopf. */
  background: var(--paper); color: var(--ink);
  display: none;
}
.lightbox[open] { display: block; }
.lightbox::backdrop { background: color-mix(in srgb, var(--paper) 92%, transparent); }

/* **Das Foto nimmt die ganze Flaeche.** Vorher stand es zwischen den Pfeilen in
   einer Spalte und war auf dem Telefon kleiner als die leere Flaeche darum -
   dabei ist genau dieses Bild der Grund, warum die Ansicht offen ist. Jetzt
   liegt es unter den Knoepfen und wird so gross gezeigt, wie es hineinpasst;
   `contain` schneidet dabei nichts ab. */
.lightbox-figure { position: absolute; inset: 0; margin: 0; }
.lightbox-figure img {
  display: block; width: 100%; height: 100%; object-fit: contain;
}
/* Der Nachweis liegt unten am Bildrand - auf hellem Streifen, weil er sonst auf
   einem hellen Foto verschwindet. Namensnennung, die man nicht lesen kann, ist
   keine. */
.lightbox-figure figcaption {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: center;
  gap: .2rem .8rem; font-size: .85rem; padding: .5rem 1rem; color: var(--soft);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
}
.lightbox-credit a { color: inherit; }
.lightbox-count { font-variant-numeric: tabular-nums; }

/* Die Knoepfe tragen `.backsquare` - hier steht nur, wo sie sitzen: das X in
   der Ecke wie in der Navigation, die Pfeile auf halber Hoehe an den Raendern,
   wo die Hand sie sucht. */
.lightbox-close { position: absolute; top: 0; right: 0; z-index: 2; }
.lightbox-step { position: absolute; top: 50%; transform: translateY(-50%); z-index: 2; }
.lightbox-step[data-step="-1"] { left: 0; }
.lightbox-step[data-step="1"] { right: 0; }

/* ---------------------------------------------------------------------------
   Die Lesespalte: schmaler als der Rahmen. Bilder bleiben breit.
   --------------------------------------------------------------------------- */

/* Aufgezaehlt statt ueber `:not()` ausgeschlossen: So steht hier, was Text ist -
   und ein neues Bauteil ist im Zweifel breit und nicht versehentlich schmal. */
#entry > h2,
#entry > .pairs,
#entry > .item-text,
#entry > .tip,
#entry > .qa,
#entry > .results,
#entry > .count,
#entry > .note,
#entry > .ratings,
#ort > h2,
#ort > .count,
.ort-abschnitt > h2,
.ort-abschnitt > .ort-mehr {
  max-width: var(--text);
}

/* **Auf der Eintragsseite steht alles auf einer Achse.**
   Seit die SVG-Karte weg ist, gibt es keine zweite Spalte mehr - Text und
   Angaben ruecken deshalb in die Mitte, wie der Kennungsblock darueber. Der Text
   selbst bleibt linksbuendig: zentrierte Absaetze liest man schlechter, weil
   jede Zeile woanders anfaengt. */
#entry > h2,
#entry > .pairs,
#entry > .qa,
#entry > .results,
#entry > .count,
#entry > .note,
#entry > .ratings,
#entry .item-body,
#entry .actions,
#entry .photo,
#entry .videoblock,
#entry .gallery,
#entry .tourmap {
  margin-left: auto; margin-right: auto;
}
/* Bild, Video, Galerie und Wegkarte bleiben breiter als der Text - sie zeigen
   etwas, sie erzaehlen nichts.

   **Das Video gehoert in dieselbe Zeile.** Ohne diese Angabe nahm es die ganze
   Rahmenbreite und stand damit breiter als die Galerie direkt darunter - zwei
   Kanten fuer dieselbe Sache. Es steht ueber den Fotos und muss deshalb genau
   so weit reichen wie sie.

   **1000 rem heisst: so breit wie der Rahmen** (06.09.2026, auf Wunsch). Der
   Wert ist keine Breite, sondern die abgeschaffte Grenze - `main` deckelt bei
   1100 px, und was hier steht, laeuft dagegen. Vorher waren es 60 rem, also
   eine zweite Kante innerhalb der ersten: ein Streifen Rand, den nichts
   erklaerte. Die vier bleiben zusammen in **einer** Regel, damit sie eine
   Kante bleiben - eine breite Galerie unter einem schmaleren Bild waere genau
   der Fehler, den der Absatz darueber beschreibt, nur andersherum. */
#entry .photo, #entry .videoblock, #entry .gallery,
#entry .tourmap { max-width: 1000rem; }
#entry .item-body { max-width: var(--text); }
/**
 * **Die Kurzbeschreibung steht auf der Achse des Kopfes.**
 *
 * Auf einer Eintrags- und einer Veranstaltungsseite sind Rubrik oder Datum,
 * Name, Ort und Wetter mittig gesetzt - und der Satz darunter beantwortet die
 * letzte Frage desselben Blocks. Linksbuendig war er das einzige Stueck, das
 * aus der Achse fiel; die Kante links hatte kein Gegenueber, weil der Text
 * kuerzer ist als seine Spalte.
 *
 * **Nur dieser eine Satz.** Der lange Text darunter (`.item-text`) bleibt
 * linksbuendig und sagt das ausdruecklich: Dort sind es Absaetze, und jede
 * Zeile faenge woanders an. Die Kurzbeschreibung ist ein bis zwei Zeilen -
 * genau die Laenge, bei der eine Mittelachse traegt.
 *
 * Die uebrigen `.lead` im Haus (Angebote, Magazin, Kalender, Beitrag) bleiben
 * linksbuendig: Dort ist auch die Ueberschrift darueber linksbuendig.
 */
#entry .item-body .lead { text-align: center; }
#entry .actions { max-width: var(--text); }
/* Der Kennungsblock ist mittig und hat seine eigene, etwas groessere Breite -
   zentrierte Zeilen brauchen mehr Rand als linksbuendige. */
.item-ident { max-width: var(--text); }

/* ---------------------------------------------------------------------------
   Die Klappe auf der Karte: was hinter einer Nadel steckt.
   --------------------------------------------------------------------------- */

/* Sie liegt **in** der Karte, unten links - nicht ueber der Seite: Sie gehoert
   zu der Nadel, die man gerade angetippt hat. Auf dem Telefon nimmt sie die
   ganze Breite, dort ist links und rechts kein Platz zu verschenken. */
/**
 * **Flach, nicht hoch.** Bild links, Text rechts - so ist die Klappe rund 6rem
 * hoch statt 16 und laesst die uebrigen Nadeln sichtbar. Eine Klappe, die die
 * Karte zudeckt, nimmt genau das weg, wofuer man sie geoeffnet hat: den
 * Vergleich mit dem, was daneben liegt.
 *
 * Sie bleibt **in** der Karte. Ueber ihren Rand hinaus waere sie ein Kasten, der
 * neben der Karte schwebt und nicht mehr zu der Nadel gehoert, die man
 * angetippt hat.
 */
/**
 * **Die Klappe haengt an der Nadel** (seit 03.09.2026) - MapLibre setzt sie
 * dorthin, wo Platz ist, und zeichnet die Spitze zum Punkt. Sie ist damit kein
 * Kasten in der Ecke mehr, sondern die Auskunft **zu diesem** Punkt.
 *
 * Deshalb steht hier keine Lage mehr, nur die Form. Das Fenster darum
 * (`.maplibregl-popup-content`) bringt die Bibliothek mit; wir nehmen ihm
 * Polster, Rundung und Schatten ab, damit es aussieht wie alles andere hier:
 * eine Flaeche mit Kante, kein Sprechblasenkasten.
 */
.mapsheet {
  width: min(18rem, 78vw);
  background: var(--paper); color: var(--ink);
  display: grid; grid-template-columns: 1fr; align-items: stretch;
  position: relative;
}
.mapsheet-popup .maplibregl-popup-content {
  padding: 0; border-radius: 0; background: none;
  box-shadow: 0 2px 14px rgba(0, 0, 0, .3);
}
/**
 * **Kein Zeiger an der Klappe** (raus am 03.09.2026). Stattdessen kehrt die
 * angeklickte Nadel ihre Farben um - dieselbe Aussage mit einem Zeichen
 * weniger, und sie stimmt auch dann, wenn die Klappe weit neben der Nadel
 * liegt, weil dort kein Platz war.
 */
.mapsheet-popup .maplibregl-popup-tip { display: none; }

.mapsheet-body { padding: .6rem .8rem .7rem; display: grid; gap: .15rem; align-content: center; }
/* The kind as a pill - the form of the place in a calendar row
   (`.terminzeile-ort`): monospace, light ground, the classification of the
   row and not its content. The place stands under the name (`.mapsheet-ort`). */
.mapsheet-kind { margin: 0 0 .15rem; }
.mapsheet-kind span {
  display: inline-block; max-width: 100%; padding: .25rem .75rem;
  border-radius: 999px; background: var(--shade);
  font-family: var(--mono); font-size: .68rem; color: var(--soft);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: top;
}
.mapsheet-name { margin: 0; font-weight: 700; font-size: .98rem; line-height: 1.25; }
.mapsheet-ort { margin: 0; font-size: .82rem; color: var(--soft); }
.mapsheet-km { margin: 0; font-size: .82rem; color: var(--soft); font-variant-numeric: tabular-nums; }
/**
 * **Der Verweis liegt am Namen und deckt die Klappe.** Dasselbe Muster wie bei
 * der Kachel: Die Klappe ist `position: relative`, das `::after` spannt sich
 * darueber, und das X liegt mit `z-index` daraufhin oben. Ein `<a>` um alles
 * ginge nicht - im Kasten sitzt ein Knopf, und ein Knopf in einem Verweis ist
 * ungueltiges Markup.
 */
.mapsheet-name a { color: inherit; text-decoration: none; }
.mapsheet-name a::after { content: ""; position: absolute; inset: 0; }
.mapsheet:hover .mapsheet-name a,
.mapsheet-name a:focus-visible { text-decoration: underline; }
.mapsheet-name a:focus-visible { outline: none; }
.mapsheet:has(.mapsheet-name a:focus-visible) { outline: 2px solid var(--strong); outline-offset: 2px; }
/* Das X sitzt im Bild, auf eigenem Grund - sonst verschwindet es darin. */
/* Das X sitzt rechts oben in der Klappe - nicht auf dem Bild: Bei einem
   schmalen Bildstreifen waere es halb darauf und halb daneben. */
/* **In der Ecke, ohne Abstand** - schwarzes Quadrat, weisses X: dieselbe Form
   wie der Zurueckknopf und die Knoepfe der Galerie. Vorher schwebte ein weisser
   Kreisknopf mit Schatten daneben; er sah aus wie etwas Eigenes, war aber
   dasselbe: eine Ansicht schliessen. */
.mapsheet-close {
  position: absolute; right: 0; top: 0; z-index: 1;
  width: 2rem; height: 2rem; padding: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  background: var(--nav); color: var(--nav-ink); border: 0;
}
.mapsheet-close:hover, .mapsheet-close:focus-visible {
  background: color-mix(in srgb, var(--nav) 82%, var(--nav-ink));
}
.mapsheet-close:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: -4px; }
.mapsheet-close svg { width: .95rem; height: .95rem; }
/**
 * **Auf dem Finger ist die Treffflaeche 44 px, das Quadrat bleibt 32.**
 *
 * Das schwarze Quadrat ist die Hausform (dieselbe wie der Zurueckknopf und die
 * Galerieknoepfe) und keine freie Groesse; WCAG 2.2 (SC 2.5.8) zaehlt aber die
 * **Treffflaeche** und nicht die Tinte. Also waechst der Griff nach innen und
 * unten, wo nur die Klappe liegt - nach aussen waere er ausserhalb.
 */
@media (pointer: coarse) {
  .mapsheet-close::before { content: ""; position: absolute; inset: -6px -6px -12px -12px; }
}

/* Die Liste unter der Karte ist ersetzt, sobald die Karte steht - sie bleibt
   aber im Dokument: Ihre Verweise sind die Verbindung zu den Nachbareintraegen.
   Steht die Karte nicht, steht die Liste. */
.results.is-replaced { display: none; }


/* ===========================================================================
   VERWEISE NACH DRAUSSEN
   ===========================================================================
   Der schraege Pfeil an jedem Verweis, der die Seite verlaesst. **Wer einen
   bekommt, entscheidet `chrome.js`** (`data-external="arrow"`), nicht dieses
   Stylesheet: Schaltflaechen und Zeilen mit eigenem Zeichen sind dort
   ausgenommen. Ein `a[target="_blank"]::after` ueber alles waere die bequeme
   Fassung - und genau die zerlegt im WordPress-Theme die Innenabstaende der
   Schaltflaechen.

   Als Maske und nicht als Schriftzeichen: `↗` ist in vielen Schriften nicht
   enthalten und wird dann als Ersatzkasten gezeichnet. Die Maske nimmt
   `currentColor` an und passt damit in beiden Modi und in jeder Farbe.

   `inline-block` mit fester Groesse statt `content: "↗"`: Der Pfeil soll die
   Zeilenhoehe nicht veraendern - sonst springt der Text um, sobald das Skript
   ihn setzt. Genau das waere ein Sprung, den wir gerade abgestellt haben. */
a[data-external="arrow"]::after {
  content: "";
  display: inline-block;
  width: .82em; height: .82em;
  margin-left: .3em;
  vertical-align: baseline;
  background-color: currentColor;
  mask: var(--icon-external) center / contain no-repeat;
  -webkit-mask: var(--icon-external) center / contain no-repeat;
  /* Der Pfeil gehoert zum Wort davor - er darf nicht allein in die naechste
     Zeile rutschen. */
  flex: none;
}
/* Der Pfeil sitzt am letzten Wort, nicht am Ende des Kastens: Ein Verweis ueber
   zwei Zeilen bekommt ihn hinter das letzte Wort, nicht darunter. Das erledigt
   `::after` von selbst - hier steht nur, dass er nicht umbrechen darf. */
a[data-external="arrow"] { text-underline-offset: .18em; }

/* ===========================================================================
   KONTO UND PRUEFLISTE
   ===========================================================================
   Zwei Arbeitsseiten, kein Schaufenster. Deshalb sparsam: Die vorhandenen
   Formularbauteile (`.feld`, `.vorschlag-form`, `.action`) tragen das meiste,
   hier steht nur, was es dort noch nicht gab. */

/* Zwei Felder nebeneinander, auf dem Telefon untereinander. Vorname und
   Nachname gehoeren in eine Zeile - es ist ein Name. */
.feld-paar { display: grid; gap: 0 1rem; }
@media (min-width: 34rem) {
  .feld-paar { grid-template-columns: 1fr 1fr; }
  /* Die PLZ braucht keine halbe Zeile - der Ort schon. */
  .feld-paar-plz { grid-template-columns: 8rem 1fr; }
}

/* Der Haken vor der Erklaerung: Kasten links, Text daneben - und der Text
   bricht unter sich um, nicht unter den Kasten. */
/* Die Bestaetigung nach dem Abschicken - an der Stelle des Formulars.

   Vorher war sie eine Zeile in .82rem am Fussende der Seite. Der Kasten ist
   dieselbe Form wie die Tipp-Box (Balken links, ganz leichter Grund, eckige
   Ecken) - eine Formensprache, nicht zwei. Der Unterschied liegt allein im
   Haken davor und darin, dass hier ein Weg weiterfuehrt.

   `.fertig .actions` ohne die 2.2rem nach unten: Der Kasten hat sein eigenes
   Polster, und der Knopf ist das Letzte darin. */
.fertig {
  max-width: var(--text); margin: 0 0 1.6rem;
  border-left: 3px solid var(--strong);
  background: color-mix(in srgb, var(--strong) 5%, transparent);
  padding: 1.1rem 1.2rem; text-align: left;
}
.fertig p { margin: 0 0 .5rem; }
.fertig p:last-child { margin-bottom: 0; }
.fertig-kopf {
  display: flex; align-items: center; gap: .5rem;
  font-size: 1.08rem; color: var(--strong);
}
.fertig-kopf .glyph { color: var(--strong); flex: none; }
.fertig .actions { margin: .9rem 0 0; }

/* ==========================================================================
   DIE BEWERTUNGSSEITE  (04.09.2026)
   ==========================================================================

   Sie hat nur drei eigene Regeln - alles andere kommt aus den vorhandenen
   Bauteilen: `.vorschlag-form`, `.feld`, `.feld-paar`, `.feld-haken`,
   `.sterne-wahl`, `.code-boxen`, `.fertig`. Genau das war die Absicht: Eine
   Seite, die zu neun Zehnteln auf einem Handy geoeffnet wird, braucht kein
   eigenes Formularsystem, sondern das vorhandene in derselben Groesse. */

/* **Der Entwurfshinweis auf einer Eintragsseite** (04.09.2026). Sie sieht aus
   wie jede andere - nur ist sie nicht oeffentlich, und das muss oben stehen.
   Dieselbe Form wie die Tipp-Box (Balken links, leichter Grund, eckig), aber in
   der Warnfarbe der Zustaende: Es ist eine Auskunft ueber den Zustand, kein
   Tipp zum Ort. */
.entwurf-hinweis {
  max-width: var(--text); margin: 1rem auto 1rem;
  border-left: 3px solid var(--state-wait-ink);
  background: var(--state-wait-bg);
  padding: .8rem 1rem;
}
.entwurf-hinweis p { margin: 0; font-size: .92rem; color: var(--ink); }

/* Der Weg zurueck zum Eintrag - **ueber** der Ueberschrift, nicht unter dem
   Formular. Wer einen QR-Code an einer Theke scannt, will als erstes
   nachsehen, ob er beim richtigen Haus ist; danach kommt das Formular. */
.bewerten-zurueck { margin: 0 0 .4rem; font-size: .9rem; }
.bewerten-zurueck a { color: var(--soft); }
/* **Der Zeitraum unter dem Namen einer Veranstaltung** - dieselbe Form wie die
   Zeile darueber: leise, eine Zeile, kein Kasten. Sie sagt, welche Ausgabe
   gemeint ist, und bei einem Datum in der Zukunft auch, dass das Fest noch
   bevorsteht. Nur bei einem Termin gesetzt, deshalb `hidden` in der Huelle. */
.bewerten-wann { margin: -.3rem 0 .8rem; font-size: .9rem; color: var(--soft); }

/* **Der Honigtopf.** Aus dem Bild genommen, aber nicht aus dem Baum: Ein
   Skript, das Formulare ausfuellt, findet ihn und faellt darauf herein.

   `display: none` waere hier der Fehler - manche Skripte ueberspringen genau
   das, und manche Browser fuellen Felder in ausgeblendeten Bloecken nicht aus.
   Deshalb dieselbe Technik wie bei `.visually-hidden`. Ein Mensch kann ihn
   nicht erreichen: Das Feld traegt `tabindex="-1"`, der Block `aria-hidden`. */
.honigtopf {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* „optional" hinter einer Feldbeschriftung - leiser als sie, in derselben
   Zeile. Ein eigener Satz darunter waere dieselbe Auskunft in drei Zeilen. */
.feld-frei {
  font-weight: 400; color: var(--soft); font-size: .82em;
  text-transform: none; letter-spacing: 0;
}

/* Die Sternewahl im Bewertungsformular.

   **Fuenf Knoepfe, keine Auswahlliste.** Sterne versteht jeder Gast in jeder
   Sprache ohne Uebersetzung, und was ohne Nachdenken geht, wird ausgefuellt -
   Rueckmeldungen sind das knappste Gut hier, jede Huerde kostet mehr, als sie
   schuetzt.

   Groesser als die Sterne an einer fertigen Stimme (30 statt 15 Pixel): Hier
   trifft man sie mit dem Finger, dort liest man sie nur. Die Farbe ist die
   Textfarbe - eine eigene Sternfarbe waere eine sechste Erkennungsfarbe neben
   den fuenf der Rubriken. */
.sterne-wahl { display: flex; gap: .2rem; }
.stern-knopf {
  border: 0; background: none; padding: .15rem; cursor: pointer;
  color: var(--line); line-height: 0;
}
.stern-knopf:hover { color: var(--soft); }
.stern-voll { color: var(--strong); }
.stern-voll svg { fill: currentColor; }
.stern-knopf:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }

/* Die Ablegeflaeche fuer Bilder - **eine** Gestaltung fuer beide Verwendungen
   (Primärbild und Profilbild), passend zur einen Komponente im Skript.

   **Gestrichelt, nicht durchgezogen.** Ein durchgezogener Rahmen sieht wie ein
   Eingabefeld aus, in das man tippt; die Strichelung sagt „hier ist Platz fuer
   etwas, das noch kommt". Ecken bleiben eckig (Styleguide).

   **Die Flaeche ist das Bedienelement, das Feld ist weg.** Sie ist ein `label`,
   das Dateifeld darin nur `visually-hidden` - also aus dem Bild genommen, aber
   nicht aus dem Baum: Ein Klick oder Tipp irgendwo auf der Flaeche oeffnet den
   Dialog, und die Tastatur erreicht das Feld weiterhin. `display: none` waere
   der Fehler an dieser Stelle, denn damit waere es auch fuer die Tastatur weg.

   Der Fokusring gehoert deshalb an die Flaeche und nicht an das Feld - `:has`
   holt ihn dorthin, wo man ihn sehen kann. */
.ablage {
  display: grid; gap: .5rem; justify-items: center; text-align: center;
  border: 2px dashed var(--line); padding: 1.4rem 1.1rem; cursor: pointer;
  transition: border-color .12s, background-color .12s;
}
.ablage:hover { border-color: var(--soft); }
.ablage:has(input:focus-visible) { border-color: var(--strong); border-style: solid; }
/* Lucide „upload". Leiser als der Text - es weist hin, es ruft nicht. */
.ablage-icon { width: 28px; height: 28px; color: var(--soft); display: block; }
.ablage-satz { margin: 0; color: var(--soft); font-size: .95rem; }
/* Auf dem Telefon gibt es kein Ziehen - dann faellt der Zusatz weg und es
   bleibt stehen, was dort wirklich moeglich ist: auswaehlen. */
@media (hover: none) {
  .ablage { border-style: solid; }
  .ablage-satz span { display: none; }
}
/* Waehrend etwas darueber haengt: derselbe Strich wie ein Fokusring, damit
   ohne Farbe erkennbar bleibt, dass die Flaeche zugreift. */
.ablage-an {
  border-color: var(--strong); border-style: solid;
  background: color-mix(in srgb, var(--strong) 5%, transparent);
}
.ablage-datei { margin: 0; font-size: .9rem; font-weight: 700; }
.ablage-datei:empty { display: none; }

/* ==========================================================================
   Profilbild und Ausschnittwaehler
   ==========================================================================

   **Rund, obwohl der Styleguide eckig sagt.** Die Regel `border-radius: 0` gilt
   der Marke - Karten, Knoepfe, Felder. Ein Bild eines Menschen ist keine
   Flaeche der Oberflaeche, sondern ein Portraet, und rund liest es sich
   ueberall als „das ist jemand" statt als „das ist ein Element". Es ist die
   einzige Ausnahme, und sie steht hier angeschrieben, damit sie keine zweite
   bekommt. */
.avatar-block {
  display: grid; grid-template-columns: auto 1fr; gap: 1.2rem;
  align-items: start; margin: 0 0 1.6rem;
}
.avatar-schau {
  width: 96px; height: 96px; border-radius: 50%;
  overflow: hidden; background: var(--shade);
  display: grid; place-items: center; flex: none;
}
.avatar-bild { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Der Platzhalter traegt die Initialen - kein Silhouetten-Symbol. Ein Kuerzel
   sagt, wessen Platz das ist; eine graue Silhouette sagt nur „leer". */
.avatar-leer {
  font-size: 2rem; font-weight: 400; color: var(--soft); letter-spacing: .02em;
}
.avatar-tat { display: grid; gap: .5rem; min-width: 0; }
.avatar-tat > span { font-weight: 700; }
.avatar-tat .ablage { padding: 1rem; }
.avatar-fuss {
  margin: 0; display: flex; flex-wrap: wrap; gap: .6rem; align-items: center;
}
.avatar-fuss .feld-hint { margin: 0; }
@media (max-width: 34rem) {
  .avatar-block { grid-template-columns: 1fr; justify-items: start; }
}

/* Der Zuschneider. Eckig wie alles andere - nur das Bild darin ist rund
   maskiert, weil es rund erscheinen wird. Was man waehlt, soll aussehen wie
   das, was danach dasteht. */
/* ===========================================================================
   DIE PINKARTE IM EDITOR - nachsehen und verschieben
   ===========================================================================

   Klein, aber nicht winzig: 260 Pixel hoch reichen, um ein Haus von der
   Strasse zu unterscheiden, und mehr wuerde das Formular auseinanderreissen.
   Rahmen wie ein Eingabefeld, denn das ist sie hier - eine Eingabe fuer zwei
   Zahlen, nur begreifbar. */
.pinmap {
  height: 260px; border: 1px solid var(--line); background: var(--shade);
  margin: .3rem 0 0;
}
/**
 * **Der Pin ist derselbe wie im Frontend** - der Tropfen mit dem Baum in der
 * Farbe der Rubrik, gezeichnet in `tourmap.js`. Hier steht nur, dass man ihn
 * anfassen kann: `grab`, und beim Ziehen `grabbing`. Ein Pin, der sich
 * verschieben laesst, ohne es zu zeigen, wird nicht angefasst.
 *
 * Vorher stand hier ein schwarzer Tropfen aus `border-radius` und `rotate` -
 * ein zweites Zeichen fuer dieselbe Sache, und im Backend ein anderes als
 * draussen.
 */
.pinmap-pin { cursor: grab; line-height: 0; }
.pinmap-pin svg { display: block; }
.pinmap-pin:active { cursor: grabbing; }

/* ===========================================================================
   LÖSCHEN - der eine Knopf, der anders aussehen muss
   ===========================================================================

   **Rot, und nur hier.** Der Guide ist schwarz auf weiss; die einzige Stelle,
   an der eine Warnfarbe etwas beitraegt, ist der Knopf, der etwas mitnimmt,
   das nicht zurueckkommt. Genommen wird die Zustandsfarbe „nicht freigegeben"
   (`--state-stop-*`) - kein neues Rot.

   Der Knopf ist **zu**, bis DELETE getippt ist; ein gesperrter Knopf, der wie
   ein Knopf aussieht, ist die einzige Form, die hier taugt: Man sieht, was
   moeglich waere, und dass es noch nicht moeglich ist. */
.action-weg {
  border-color: var(--state-stop-ink); background: var(--state-stop-ink); color: var(--paper);
}
.action-weg:hover:not(:disabled) {
  background: color-mix(in srgb, var(--state-stop-ink) 84%, black);
}
.action-weg:disabled { opacity: .45; cursor: not-allowed; }

/* Was das Löschen verhindert - ein Satz, der oben steht und nicht wegzulesen ist. */
.weg-halt {
  margin: 0 0 1rem; padding: .7rem .9rem;
  background: var(--state-stop-bg); color: var(--state-stop-ink);
  border-left: 4px solid var(--state-stop-ink); font-size: .95rem;
}
.weg-satz { margin: 0 0 .3rem; font-weight: 700; font-size: .95rem; }
.weg-liste { margin: 0 0 1rem; padding-left: 1.2rem; font-size: .95rem; }
.weg-liste li { margin: .15rem 0; }

/* ===========================================================================
   DAS DASHBOARD - eine Zahl, eine Kurve, ein paar Balken
   ===========================================================================

   Karten nebeneinander, in jeder oben der Titel, darunter ein Satz, dann die
   **grosse Zahl** und die Kurve. Die Form kommt aus einem Vorbild
   (05.09.2026); uebernommen ist die **Anordnung**, nicht die Gestaltung: keine
   runden Ecken, keine blauen Linien, kein Schatten - schwarz auf weiss, ein
   Strich als Rahmen.

   Zwei Karten nebeneinander ab 62 rem: Auf einem schmalen Schirm ist eine
   Kurve neben einer Kurve keine Uebersicht, sondern zwei Briefmarken. */
.dash {
  display: grid; gap: 1rem; margin: 0 0 2rem;
}
@media (min-width: 62rem) {
  .dash { grid-template-columns: 1fr 1fr; }
  /* **Eine Karte mit vielen Kacheln nimmt beide Spalten.** Das Raster darin
     steht auf `minmax(9rem, 1fr)`: In einer halben Spalte sind vierzehn
     Kanaele vier gedraengte Reihen auf Mindestbreite, ueber die ganze Breite
     zwei ruhige. Wer sie traegt, entscheidet `anteileMarkup` an der Zahl der
     Zeilen - hier steht nur, was „breit" heisst. */
  .dash > .dash-breit { grid-column: 1 / -1; }
}
/**
 * **Die Statistikkachel ist weiss, wirft einen Schatten und hat weiche Ecken.**
 *
 * Das ist eine **ausdrueckliche Ausnahme** von `border-radius: 0` und von
 * „eine Kachel ist flach" - und sie gilt **nur im Backend**. Draussen sind das
 * zwei tragende Regeln der Marke; hier steht ein Messblatt, das man liest wie
 * ein Dokument, und eine Zahl auf einer eigenen Flaeche liest sich schneller
 * als eine Zahl in einer Spalte.
 *
 * **Kein Rahmen - die Grenze ist der Helligkeitsschritt zum Grund.** Die
 * Kachel steht auf `--card-ground`, die Seite auf `--backend-ground`, und
 * beide Werte gibt es in hell und dunkel. Ein Strich daneben waere die zweite
 * Antwort auf dieselbe Frage, und er gewinnt sie immer: Man saehe einen Kasten
 * mit Schlagschatten statt einer Flaeche, die liegt.
 */
/**
 * **Die Kachelform steht an einer Stelle, drei Flaechen lesen sie:** die Karte
 * selbst, die Zahl darin und die Anteilskacheln darunter. Dreimal
 * ausgeschrieben waeren es drei Stellen, an denen eine Ecke oder ein Schatten
 * auseinanderlaeuft - und man saehe es erst nebeneinander.
 */
.dash-karte,
.dash-zahl,
.stat-kachel {
  background: var(--card-ground);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
}
.dash-karte {
  padding: 1.2rem 1.3rem 1rem;
  display: flex; flex-direction: column;
}

/**
 * **Schluessel und Wert stehen je auf einer eigenen kleinen Kachel.**
 *
 * Der Wert oben in der Grotesk, der Schluessel darunter in der Monospace -
 * dieselbe Regel wie an jeder Kennzahl: **Grotesk sagt was, Monospace sagt
 * woher.** Die Schiene darunter gibt es erst ab 30 Aufrufen; bei 2 von 4 sieht
 * eine halb gefuellte Schiene aus wie bei 100 von 200.
 *
 * Das Raster fuellt sich selbst auf: `auto-fill` statt einer festen
 * Spaltenzahl, damit vier Geraetezeilen und vierzehn Kanaele dieselbe Regel
 * teilen.
 */
.stat-kacheln {
  list-style: none; margin: 1rem 0 0; padding: 0;
  display: grid; gap: .6rem;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
}
.stat-kachel { padding: .7rem .8rem .8rem; }

/**
 * **Die Regeln stehen hinter der Grundregel**, nicht im Layoutblock weiter
 * oben: Dort haetten sie dieselbe Spezifitaet und verloeren gegen das
 * `auto-fill`, das `.stat-kacheln` gleich darueber setzt. Dieselbe Falle wie
 * beim Ziehgriff, beim Polster der Spalte und beim Kopf auf dem Telefon.
 */
@media (min-width: 62rem) {
  /**
   * **Die Kacheln teilen sich die Breite ihrer Karte.**
   *
   * Die Spaltenzahl kommt als Wert aus `anteileMarkup`: bis drei je eine
   * Spalte, darueber die Haelfte, aufgerundet - also zwei Reihen. Mit
   * `auto-fill` standen zwei Geraete oder drei Sprachen links und liessen
   * rechts eine Luecke, als fehle etwas; neun Kanaele dagegen wurden zu neun
   * Streifen, in denen der Name unter der Zahl umbrach.
   *
   * `minmax(0, 1fr)` und nicht `9rem`: Die Kachel soll sich teilen, was da
   * ist, und nicht eine Mindestbreite verlangen, die in einer halben Karte
   * ueberlaeuft.
   *
   * **Nur am Schirm:** Auf einem Telefon waeren fuenf feste Spalten fuenf
   * Kruemel, und `auto-fill` ist dort genau richtig.
   */
  /**
   * **Die Kacheln teilen sich die Flaeche - auch in der letzten Reihe.**
   *
   * Ein Raster haelt seine Spalten: Neun Kacheln auf fuenf Spuren sind fuenf
   * und vier, und die vier hoeren dort auf, wo die fuenfte Spur beginnt -
   * rechts bleibt ein Fuenftel der Karte leer. Ein Flexlauf verteilt den Rest
   * stattdessen auf die Kacheln, die da sind.
   *
   * Die **Grundbreite** ist genau eine Spur (die Breite minus die Fugen,
   * geteilt durch die Spaltenzahl) - damit brechen sie an derselben Stelle um
   * wie im Raster. Was in der letzten Reihe uebrig bleibt, waechst hinein.
   */
  .stat-kacheln {
    display: flex; flex-wrap: wrap;
  }
  .stat-kacheln > .stat-kachel {
    flex: 1 1 calc(
      (100% - (var(--kachel-spalten, 1) - 1) * .6rem) / var(--kachel-spalten, 1)
    );
  }
  /**
   * **Eine Karte ist so breit wie ihre Kacheln, nicht wie ihre Spur.**
   *
   * Zwei gleich breite Spuren passten zu zwei gleich grossen Karten - die
   * Anteilskarten sind aber verschieden gross: zwei Geraete, drei Sprachen,
   * eine Klickart. In einem Raster aus Haelften stand daher neben drei
   * Sprachen eine Luecke und unter ihnen eine einzelne Kachel ueber eine
   * halbe Seite.
   *
   * **Also zaehlt das Raster Kacheln, nicht Karten:** sechs Spuren, und jede
   * Karte nimmt so viele, wie sie Kacheln hat. 2 + 3 + 1 ergibt sechs und
   * damit **eine** Reihe; „Woher sie kommen" mit neun nimmt alle sechs und
   * steht darunter. Kommt eine Sprache dazu, sind es sieben - dann bricht die
   * Reihe um, und das ist richtig: Sieben Kacheln nebeneinander waeren sieben
   * Streifen.
   */
  /**
   * **Die Anteilskarten teilen sich eine Reihe nach ihrer Groesse.**
   *
   * Sie stehen als eigener Lauf ueber die ganze Breite des Blattes; darin
   * bekommt jede Karte so viel Platz, wie sie Kacheln hat (zwei Geraete zu
   * drei Sprachen also 2 : 3). Ein Raster aus gleichen Spuren ginge nicht
   * auf - zwei und drei sind fuenf, und eine sechste Spur bliebe leer.
   *
   * Die Kurvenkarten darueber bleiben, wo sie waren: Sie stehen nicht in
   * diesem Lauf und behalten ihre zwei Spuren.
   */
  .dash-anteile {
    grid-column: 1 / -1;
    display: flex; flex-wrap: wrap; gap: 1rem;
  }
  .dash-anteile > .dash-karte { flex: var(--kachel-spalten, 1) 1 0; min-width: 0; }
  /* Die breite Karte faengt eine eigene Zeile an - ihre Kacheln sind die, an
     denen die anderen sich messen. */
  .dash-anteile > .dash-breit { flex-basis: 100%; }
}
.stat-wert {
  margin: 0; font-size: 1.35rem; font-weight: 700; line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
/* Der Nenner gehoert zur Zahl, ist aber nicht die Aussage - leiser und
   kleiner, damit „780" das ist, was man zuerst liest. */
.stat-von { font-weight: 400; font-size: .82rem; color: var(--soft); }
.stat-kachel .stat-note { margin: .15rem 0 0; }

/* The range on `#/besucher` stands apart from the cards below it - a
   descendant selector: the area is wrapped into `.bk-tafel` at runtime. */
#bereich-besucher .schnitt { margin-bottom: .75rem; }

/*
 * Consent answers on `#/besucher`: allowed in the state green, declined in the
 * state red mixed toward the ground - far apart in lightness, so the two stay
 * apart for red-green weak eyes too (checked: CVD dE 26.8 light, 27.6 dark,
 * both >= 3:1 against the ground). A 2px gap between the parts; the words
 * beside them carry the meaning, the colour only repeats it.
 */
.consent-meter {
  display: flex;
  gap: 2px;
  height: .6rem;
  margin: .5rem 0 .35rem;
}
.consent-meter span { min-width: 2px; }
.consent-meter [data-answer="granted"],
.consent-legend [data-answer="granted"] { background: var(--state-live-ink); }
.consent-meter [data-answer="denied"],
.consent-legend [data-answer="denied"] { background: color-mix(in srgb, var(--state-stop-ink) 55%, var(--paper)); }
/* Swatch and word stay together; the two pairs wrap as wholes. */
.consent-legend {
  display: flex; flex-wrap: wrap; column-gap: .75rem;
  font-size: .82rem; color: var(--strong);
}
.consent-item { white-space: nowrap; }
.consent-legend [data-answer] {
  display: inline-block; width: .6rem; height: .6rem; margin-right: .3rem;
}

/*
 * Reading time in four buckets (`#/besucher`): one bar, more contrast means
 * longer. A one-pixel gap keeps the lightest part apart from the next one;
 * the line colour shows only on a row without measurements. Tokens only.
 */
.read-time-bar {
  display: inline-flex;
  gap: 1px;
  width: 6rem;
  height: .5rem;
  vertical-align: middle;
}
.read-time-bar[data-empty] { background: var(--line); }
.read-time-bar span { min-width: 0; }
.read-time-bar [data-bucket="0"] { background: color-mix(in srgb, var(--strong) 25%, var(--paper)); }
.read-time-bar [data-bucket="1"] { background: color-mix(in srgb, var(--strong) 50%, var(--paper)); }
.read-time-bar [data-bucket="2"] { background: color-mix(in srgb, var(--strong) 75%, var(--paper)); }
.read-time-bar [data-bucket="3"] { background: var(--strong); }
.stat-kachel .dash-schiene { margin-top: .5rem; }
/**
 * **Die Kurve in der Kachel ist breit, nicht quadratisch.**
 *
 * In der Kennzahlenreihe steht sie als 36er Quadrat **neben** der Zahl - dort
 * ist sie eine Abbildung neben einer Aussage. Hier liegt sie **unter** dem
 * Bruch und ueber der Schiene, und das Mass der Kachel ist ihre Breite: Sie
 * zeigt dreissig Tage, und dreissig Punkte auf 36 Pixeln sind ein Strich.
 *
 * Kein eigener Grund und kein Rahmen - die Kachel ist die Flaeche, auf der sie
 * liegt. Und leiser als die Schiene darunter: Die sagt den **Anteil**, die
 * Kurve nur, wann er entstanden ist.
 */
.stat-kachel .mini-kurve {
  width: 100%; height: 1.6rem; padding: 0;
  margin: .45rem 0 0; background: none; border-radius: 0; box-shadow: none;
  stroke: var(--soft);
}
.dash-karte h2 { margin: 0; font-size: 1.05rem; }
.dash-satz { margin: .2rem 0 0; color: var(--soft); font-size: .86rem; }
/* Die Zahl ist die Aussage - alles andere erklaert sie nur. */
/* Die Zahl steht auf einer eigenen Kachel - das Polster ersetzt den Abstand,
   den sie vorher als blosser Absatz hatte. `line-height: 1` an einer 2,2-rem-
   Zahl schneidet die Unterlaenge knapp; das untere Polster gleicht es aus. */
.dash-zahl {
  margin: 1rem 0 .2rem; padding: .8rem .9rem .9rem;
  font-size: 2.2rem; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums;
  /**
   * **Die Kachel ist so breit wie ihre Zahl, hoechstens halb so breit wie die
   * Karte.** Die Karte ist eine Spalte (`flex-direction: column`), und ein
   * Kind darin wird von sich aus so breit wie sie - eine Kachel mit „780" und
   * einer Handbreit Weiss daneben sieht aus wie ein leeres Feld.
   *
   * `align-self: flex-start` nimmt ihr das Strecken, `max-width: 50%` deckelt
   * den Fall, in dem der Zusatz darunter lang ist und die Kachel sonst doch
   * ueber die Karte liefe. Der Zusatz bricht dann um, und das ist richtig: Die
   * Zahl ist die Aussage, der Zusatz haengt an ihr.
   */
  align-self: flex-start; max-width: 50%;
}
.dash-zusatz {
  display: block; font-size: .82rem; font-weight: 400; color: var(--soft);
  margin-top: .3rem;
}

/**
 * ===========================================================================
 * **GROTESK SAGT WAS, MONOSPACE SAGT WOHER**
 * ===========================================================================
 *
 * Eine Kennzahl besteht aus zwei Teilen, und sie tragen verschiedene Schrift:
 *
 * | Teil | Schrift | Beispiel |
 * |---|---|---|
 * | die **Aussage** | Inter, fett, gross | „780", „3 → 14", „4,8 Mio." |
 * | die **Anmerkung** | Monospace, grau, klein | „von 1240 Aufrufen", „seit 2012" |
 *
 * **Die Zahl selbst bekommt keine Monospace.** Sie ist das, worauf es
 * ankommt, und Inter setzt sie mit Tabellenziffern ohnehin gleich breit. Was
 * die Monospace bekommt, ist die Zeile **daneben**: Bezeichnung, Bezugsgroesse,
 * Zeitraum, Herkunft. Sie wirkt technisch, und das ist hier die Aussage -
 * „diese Zahl kommt aus einer Messung, nicht aus einer Meinung".
 *
 * **Sie steht im Backend, nicht draussen.** Ein Gast liest Saetze, kein
 * Messprotokoll. Der Guide hat draussen genau eine Monospace-Flaeche, den
 * Vorteilscode, und die bedeutet etwas anderes: „das tippst du ab".
 *
 * **`.stat-note` ist das Bauteil**, die uebrigen Selektoren sind die Flaechen,
 * die es heute schon gibt. Wer eine neue Kennzahl baut, nimmt `.stat-note` und
 * erweitert diese Liste nicht.
 *
 * **Die Grenze liegt bei zwei Zeilen.** Monospace liest sich als Flaeche
 * schlechter als eine Grotesk; als kurze Anmerkung traegt sie, als Absatz
 * nicht. Was laenger wird, geht zurueck in `--font`.
 */
.stat-note,
.dash-satz,
.dash-zusatz,
/* Die Beschriftung unter einer Kurve - „Okt" links, „Sep" rechts. Sie sagt,
   welchen Zeitraum die Flaeche darueber abdeckt, ist also eine Anmerkung zur
   Abbildung und keine Aussage fuer sich. */
.dash-achse,
/* „vor einem Jahr 42" - dieselbe Sorte Anmerkung wie die Legende darueber:
   eine Bezugsgroesse, keine Aussage fuer sich. */
.dash-vergleich,
/* Der Satz unter einer Zahl der Uebersichtsleiste - „791 Aufrufe" oben, hier
   steht, worauf sie sich bezieht. Dieselbe Rolle wie `dash-zusatz`. */
.bk-zahl-zusatz,
/* Der **ganze** Kopf einer Balkenzeile, nicht nur die Zahl darin: Name und
   Bruch sind zusammen die Anmerkung zum Balken darunter. Nur die Zahl in der
   Monospace waeren zwei Schriften in einer Zeile. */
.dash-balken-kopf,
.herkunft-zahl,
.reiter-zahl,
.qr-wert,
.hb-zaehler {
  font-family: var(--mono);
}
/* Die Anmerkung unter einer Kennzahl, wenn sie kein eigenes Bauteil hat. */
.stat-note {
  margin: .3rem 0 0; font-size: .82rem; color: var(--soft);
  font-variant-numeric: tabular-nums;
}
/**
 * **Die Kurve fuellt, was uebrig ist.** `margin-top: auto` schiebt sie an den
 * unteren Rand - so stehen zwei Karten mit verschieden langen Saetzen trotzdem
 * mit ihren Kurven auf einer Linie.
 *
 * `preserveAspectRatio="none"` zieht die zwoelf Punkte auf die Breite der
 * Karte: Die Kurve soll die Entwicklung zeigen, nicht ein Seitenverhaeltnis
 * halten. Die Strichstaerke bleibt davon unberuehrt
 * (`vector-effect="non-scaling-stroke"`) - sonst waere die Linie waagerecht
 * gedehnt und saehe an flachen Stellen dicker aus.
 */
.dash-flaeche-rahmen { position: relative; margin-top: auto; }
.dash-kurve { display: block; width: 100%; height: 5.5rem; }
/**
 * **Der Punkt am Ende der Kurve - das Jetzt** (05.09.2026, nach dem Vorbild).
 *
 * Er liegt **ueber** dem SVG und nicht darin: `preserveAspectRatio="none"`
 * zieht die Kurve auf die Kartenbreite, und ein Kreis darin wuerde zur
 * Ellipse. Hier ist er ein Element mit fester Groesse; nur seine Hoehe kommt
 * aus der Rechnung (`top` in Prozent).
 *
 * **Er blinkt nicht, er atmet**: ein Ring, der aufgeht und verschwindet. Ein
 * hartes Blinken zieht den Blick immer wieder weg - eine Karte, die man ansieht,
 * soll nicht um Aufmerksamkeit bitten, sie hat sie schon. Wer Bewegung
 * abgestellt hat, bekommt den Punkt ohne Ring: Die Aussage steht in seiner
 * Lage, nicht in der Bewegung.
 */
.dash-jetzt {
  position: absolute; right: 0; width: .55rem; height: .55rem;
  border-radius: 50%; background: var(--chart);
  transform: translate(50%, -50%);
  animation: dash-atem 2.4s ease-out infinite;
}
/* The ring is the dot's own colour: it is the end of *this* line, and a black
   dot on a green curve would be a second colour for one thing. */
@keyframes dash-atem {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--chart) 45%, transparent); }
  70% { box-shadow: 0 0 0 .5rem color-mix(in srgb, var(--chart) 0%, transparent); }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--chart) 0%, transparent); }
}
@media (prefers-reduced-motion: reduce) {
  .dash-jetzt { animation: none; }
}
/* The area is the line, thinned out: one colour, two weights. A grey fill
   under a green line would read as two figures lying on top of each other. */
.dash-flaeche { fill: color-mix(in srgb, var(--chart) 22%, transparent); }
/**
 * **Ein Pixel, wie jede Kurve im Backend** (07.09.2026).
 *
 * Sie stand auf 2 und war damit die einzige Kurve hier, die dicker als die
 * kleine (`.mini-kurve`, seit jeher 1) war - zwei Staerken fuer dieselbe
 * Abbildung, nur in zwei Groessen. Auf 5,5 rem Hoehe ist ein Zweipixelstrich
 * dazu ein Band: Die Bewegung, um die es geht, verschwindet in der Staerke.
 * Das war das Argument, mit dem die kleine Kurve schon dasteht.
 *
 * Es sind **echte** Pixel: `vector-effect="non-scaling-stroke"` steht am Pfad,
 * weil `preserveAspectRatio="none"` das SVG waagerecht dehnt. Ohne das waere
 * „1" eine Zahl in Nutzereinheiten und der Strich an flachen Stellen doppelt
 * so dick wie an steilen.
 */
.dash-linie { fill: none; stroke: var(--chart); stroke-width: 1; }
/* **The zero line** - a pale grey line at the foot of the curve. It says where
   zero is, and that is the one thing the area cannot say: thirty days of
   nothing collapse the area, and this line stays.

   **It is drawn below the area** (the path order in `karteMarkup`): grey over
   green is a *lighter* hairline under the area in light mode and nothing at all
   in dark (1.04 : 1). Underneath, it shows exactly where nothing covers it.

   **Same width as the curve, and grey.** A flat curve runs right along it, and
   two lines on top of each other must be equally wide - otherwise the eye sees
   the offset instead of the thing. Grey is what keeps it quiet, not thinness. */
.dash-grund { stroke: var(--line); stroke-width: 1; }
.dash-achse {
  display: flex; justify-content: space-between;
  margin: .3rem 0 0; font-size: .78rem; color: var(--soft);
}
.dash-vergleich { margin: .1rem 0 0; font-size: .78rem; color: var(--soft); }

/* Die Balkenkarte: Zeile, Zahl, Schiene. Die Zahl daneben sagt es genau, der
   Balken sagt es schnell.

   **Der Balken traegt dieselbe Farbe wie die Kurve** (`--chart`), weil er im
   **selben** Raster neben ihr steht: `karteMarkup` und `balkenMarkup` fuellen
   auf `#/ueberblick` und unter „Mein Eintrag > Zahlen" dieselbe `.dash`. Zwei
   Farben nebeneinander behaupten zwei Sorten Auskunft, und es ist eine - eine
   gemessene Groesse. Das ist eine Farbe **weniger**, keine mehr.

   Die Schiene bleibt grau (`--line`): Sie ist der Rest bis zur Summe, nicht der
   Wert. Fuellung gegen Schiene sind 5,4 : 1 hell und 3,7 : 1 dunkel, beide ueber
   den 3 : 1, die eine Flaeche ohne Text braucht. Kein zweites Grau und keine
   Ampel - eine Ampel waeren zwei Farben, das hier ist eine. */
.dash-balken { list-style: none; margin: 1rem 0 0; padding: 0; }
.dash-balken li + li { margin-top: .8rem; }
.dash-balken-kopf {
  display: flex; justify-content: space-between; gap: 1rem;
  margin: 0 0 .3rem; font-size: .9rem;
}
.dash-balken-kopf span { color: var(--soft); font-variant-numeric: tabular-nums; }
.dash-schiene { display: block; height: .5rem; background: var(--line); }
.dash-fuellung { display: block; height: 100%; background: var(--chart); }

/* ===========================================================================
   REITER - ein Ausschnitt wird gewaehlt, nicht angeklickt
   ===========================================================================

   **Form nach dem Vorbild der Abschnittnavigation**: der aktive schwarz und
   fett, mit einem Strich - hier unten statt links, weil die Reiter waagerecht
   stehen. Kein Kasten, kein Rahmen, keine Farbe: Es ist dieselbe Aussage wie in
   der Navigation („hier bist du"), also dieselbe Sprache.

   Die Zahl steht klein daneben und ist kein Etikett: Sie sagt, wie viel
   dahinter liegt, und niemand soll sie zuerst lesen. Auf dem Telefon rollt die
   Leiste seitlich - acht Reiter passen dort nicht, und umbrechen wuerde die
   Zeile in drei verwandeln. */
.reiter-leiste {
  display: flex; gap: .2rem;
  /**
   * **Waagerecht rollen, senkrecht nicht** (04.09.2026).
   *
   * Hier stand nur `overflow-x: auto`. Ein Kasten kann aber nicht in einer
   * Achse rollen und in der anderen ueberlaufen: CSS macht aus dem `visible`
   * der zweiten Achse stillschweigend ein `auto` - und Chrome zeigte einen
   * **senkrechten** Rollbalken fuer einen einzigen Pixel Ueberstand.
   */
  overflow-x: auto; overflow-y: hidden;
  margin: 0 0 .8rem;
  /**
   * **Die graue Linie liegt *innen*, nicht als Rand** (04.09.2026).
   *
   * Sie war ein `border-bottom`, und der aktive Reiter zog sich mit
   * `margin-bottom: -1px` einen Pixel darueber, um sie zu decken. Zwei Dinge
   * gingen dabei schief: Der Ueberstand war der Grund fuer den senkrechten
   * Rollbalken - und als der weggeklippt war, stand der schwarze Strich
   * **ueber** der grauen Linie statt auf ihr (gemeldet am selben Abend).
   *
   * Ein `inset`-Schatten liegt im Innenraum des Kastens. Der 2px-Strich des
   * Reiters sitzt an derselben inneren Kante und **deckt** ihn damit - ohne
   * negativen Rand, ohne Ueberstand, ohne Rollbalken.
   */
  box-shadow: inset 0 -1px 0 var(--line);
}
.reiter {
  flex: none; border: 0; background: none; font: inherit; cursor: pointer;
  color: var(--soft); padding: .5rem .7rem;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.reiter:hover { color: var(--strong); }
/**
 * **Der aktive Reiter wird nicht fett** (07.09.2026).
 *
 * Er war es, und das kostete an jeder der fuenf Reiterleisten dasselbe: Fett
 * ist breiter als normal, also ruecken beim Umschalten alle Reiter rechts
 * daneben ein Stueck weiter - die Leiste zappelt unter dem Finger, und wer
 * zwei Reiter hintereinander antippt, trifft beim zweiten Mal daneben. Auf dem
 * Telefon, wo die Leiste ohnehin waagerecht rollt, verschiebt sich dazu der
 * Rollstand.
 *
 * Die Regel „ein Unterschied nie nur ueber Farbe" bleibt gewahrt: Der
 * **2px-Strich** unter dem Reiter ist der Unterschied in der Form, die Farbe
 * kommt dazu. Fett war die dritte Auszeichnung fuer denselben einen Zustand.
 */
.reiter[aria-selected="true"] {
  color: var(--strong); border-bottom-color: var(--strong);
}
.reiter:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
.reiter-zahl { color: var(--soft); font-size: .82rem; font-variant-numeric: tabular-nums; }
/* **Der Schnitt quer zu den Reitern** - „Nur ohne Bild" in der Terminliste.

   Er steht **unter** der Reiterleiste und nicht darin: Die Reiter sind eine
   Stufe im Ablauf und schliessen sich gegenseitig aus, der Haken schneidet
   quer dazu. In der Leiste waere er ein vierter Reiter, der sich anders
   verhaelt als die drei daneben.

   Kein gruener Schalter: Gruen heisst hier „steht auf der Startseite" (die
   Spalte in derselben Tabelle), und dieselbe Farbe fuer einen Filter waere
   eine zweite Bedeutung fuer ein Zeichen, das schon eine hat. */
.reiter[aria-selected="true"] .reiter-zahl { color: var(--strong); }
/* Die Tafel nimmt den Fokus (`tabindex="0"`), damit man vom Reiter aus mit der
   Tabulatortaste in die Tabelle kommt - ohne Rahmen drumherum. */
#eintraege-tafel:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }

/* ===========================================================================
   DER BESTAND ALS TABELLE - Kopf, Spalten, zwei Verweise und eine Auswahl
   ===========================================================================

   **Zweihundert Zeilen wollen Spalten.** Vorher war jede Zeile ein kleiner
   Absatz - gut lesbar einzeln, unvergleichbar zu zwanzig. Jetzt stehen die
   vier Fragen (Zustand, Bild, Text, Zeiten) untereinander, und man sieht mit
   einem Blick, wo etwas fehlt.

   **Keine Zebrastreifen und keine Rahmen um jede Zelle**: eine Linie zwischen
   den Zeilen, sonst nichts. Der Kopf klebt, weil man beim Blaettern sonst
   raten muss, welche Spalte man liest. */
/**
 * **Alle Zeilen untereinander, kein eigener Rollbereich** (04.09.2026).
 *
 * Zwei Fassungen sind hier gescheitert, und beide an derselben Sache: einem
 * klebenden Tabellenkopf. Erst klebte er an `var(--navheight)` in einem
 * Behaelter mit `overflow-x: auto` - CSS macht aus dem `visible` der zweiten
 * Achse stillschweigend ein `auto`, und der Kopf legte sich beim Scrollen
 * **ueber die erste Zeile** und schnitt sie an. Dann bekam der Behaelter eine
 * Hoechsthoehe, damit er wirklich rollt - und rollte damit **in** der Seite,
 * ein Kasten im Kasten, den man nicht will: Der Auftraggeber hat entschieden,
 * **alle untereinander ist besser**.
 *
 * Also: **kein klebender Kopf und keine Hoechsthoehe.** Die Seite rollt, die
 * Tabelle steht ganz da. Waagerecht rollt der Behaelter weiter - auf dem
 * Telefon ist eine Tabelle mit sechs Spalten breiter als der Schirm, und eine
 * **Seite**, die seitlich wandert, ist kaputt.
 */
.tab-rollt { overflow-x: auto; }
.bestand-tabelle {
  width: 100%; border-collapse: collapse; font-size: .92rem;
}
/**
 * ===========================================================================
 * **DIE SPALTENBREITEN STEHEN FEST** (04.09.2026)
 * ===========================================================================
 *
 * Vorher rechnete der Browser sie aus dem Inhalt aus (`table-layout: auto`),
 * und das Ergebnis war schief: Die Titelspalte bekam den ganzen freien Platz,
 * weil ihr Inhalt der laengste ist - auch dann, wenn kein Titel so lang war.
 * Die drei Punktspalten standen dafuer breit und leer nebeneinander.
 *
 * `fixed` heisst: Die erste Zeile entscheidet, und wir sagen ihr die Anteile.
 * Nebenbei ist es die schnellere Rechnung - der Browser muss nicht erst alle
 * zweihundert Zeilen messen.
 *
 * **Nur fuer den Bestand** (`data-art="bestand"`): Der Eingang hat fuenf ganz
 * andere Spalten, und feste Anteile waeren dort an jeder falsch.
 */
.bestand-tabelle[data-art="bestand"] { table-layout: fixed; }
/* **Der Name bekommt, was die Optionen abgeben** (auf Wunsch): Dort stehen
   zwei kurze Verweise („Bearbeiten", „Einladen"), hier der Eintragsname samt
   Primärbild - und der ist das, wonach man in einer Liste von zweihundert
   sucht. 28 -> 33 %, die Optionen 18 -> 13 %; die Summe bleibt 100. */
.bestand-tabelle[data-art="bestand"] th:nth-child(1) { width: 30%; }  /* Eintrag */
.bestand-tabelle[data-art="bestand"] th:nth-child(2) { width: 18%; }  /* Ort & Art */
.bestand-tabelle[data-art="bestand"] th:nth-child(3) { width: 13%; }  /* Status */
.bestand-tabelle[data-art="bestand"] th:nth-child(4),
.bestand-tabelle[data-art="bestand"] th:nth-child(5),
.bestand-tabelle[data-art="bestand"] th:nth-child(6) { width: 7%; }   /* die Punkte */
/* Der Schalter braucht seine 2,4 rem und den Kopf „Startseite" darueber. */
.bestand-tabelle[data-art="bestand"] th:nth-child(7) { width: 12%; }  /* Startseite */
.bestand-tabelle[data-art="bestand"] th:nth-child(8) { width: 13%; }  /* Optionen */
/**
 * **Die Termine tragen dieselbe Tabelle** (09.09.2026) - dieselben Bauteile,
 * dieselbe Ordnung, nur sechs Spalten statt sieben: Am Eintrag stehen drei
 * Punkte (Text, Zeiten, Adresse), an einer Veranstaltung zwei (Text, Karte).
 *
 * Zwei Tabellen, die dieselbe Arbeit tun und anders aussehen, sind zwei
 * Bedienungen - also stehen hier nur die Anteile, alles andere gilt schon.
 */
/* Fuenf Spalten: „Text" und „Karte" sind am 10.09.2026 weggefallen - die Frage
   an einen Termin ist „laeuft der noch, und steht er oben". */
.bestand-tabelle[data-art="termine"] { table-layout: fixed; }
.bestand-tabelle[data-art="termine"] th:nth-child(1) { width: 36%; }  /* Veranstaltung */
.bestand-tabelle[data-art="termine"] th:nth-child(2) { width: 28%; }  /* Ort & Termin */
.bestand-tabelle[data-art="termine"] th:nth-child(3) { width: 14%; }  /* Status */
.bestand-tabelle[data-art="termine"] th:nth-child(4) { width: 10%; }  /* Startseite */
.bestand-tabelle[data-art="termine"] th:nth-child(5) { width: 12%; }  /* Optionen */
/**
 * **Auf dem Telefon fallen die drei Punkte weg** (05.09.2026).
 *
 * „Text", „Zeiten" und „Adresse" sind Maengel, keine Auskunft: Sie sagen, was
 * an einem Eintrag noch zu tun ist. Auf 375 Pixeln kostet jede der drei
 * Spalten so viel Breite wie der Name selbst - und der ist das, wonach man in
 * einer Liste sucht. Was uebrig bleibt, ist die Frage, mit der man die Liste
 * oeffnet: **welcher Eintrag, in welchem Zustand, und wie komme ich hinein.**
 *
 * Die Punkte sind damit nicht verloren, sondern **einen Griff weiter**: im
 * Editor, wo man sie ohnehin behebt. Verborgen wird die ganze Spalte (Kopf und
 * Zelle), nicht nur ihr Inhalt - eine leere Spalte mit Ueberschrift waere eine
 * Auskunft, die nichts sagt.
 */
@media (max-width: 46rem) {
  .bestand-tabelle[data-art="bestand"] th:nth-child(4),
  .bestand-tabelle[data-art="bestand"] th:nth-child(5),
  .bestand-tabelle[data-art="bestand"] th:nth-child(6),
  .bestand-tabelle[data-art="bestand"] td:nth-child(4),
  .bestand-tabelle[data-art="bestand"] td:nth-child(5),
  .bestand-tabelle[data-art="bestand"] td:nth-child(6) { display: none; }
  /* Die frei gewordenen 21 % gehen an die vier, die bleiben - der Schalter
     bleibt stehen: Er ist eine Handlung, kein Mangel. */
  .bestand-tabelle[data-art="bestand"] th:nth-child(1) { width: 30%; }  /* Eintrag */
  .bestand-tabelle[data-art="bestand"] th:nth-child(2) { width: 18%; }  /* Ort & Art */
  .bestand-tabelle[data-art="bestand"] th:nth-child(3) { width: 18%; }  /* Status */
  .bestand-tabelle[data-art="bestand"] th:nth-child(7) { width: 14%; }  /* Startseite */
  .bestand-tabelle[data-art="bestand"] th:nth-child(8) { width: 20%; }  /* Optionen */
}
/**
 * **Die kleine Kurve vor dem Eintrag** (05.09.2026).
 *
 * Dreissig Tage Aufrufe auf zwoelf Millimetern: kein Raster, keine Achse, kein
 * gefuellter Grund - eine Linie und eine Zahl. Auf dieser Groesse ist alles
 * andere Zierde, und die Linie beantwortet die Frage schon („wird es mehr?").
 */
.anspruch-zeile { display: flex; align-items: center; gap: .7rem; }
.anspruch-kurve { display: flex; align-items: center; gap: .5rem; flex: none; }
/**
 * **Die Kurve steht auf ihrem eigenen Grund** (05.09.2026): heller Kasten mit
 * leicht gerundeten Ecken, damit sie in der Zeile als **Abbildung** lesbar ist
 * und nicht als Strich zwischen Wörtern.
 *
 * `--paper` und nicht `#fff`: Im Dunkelmodus ist der Grund der Seite dunkel,
 * und ein hart gesetztes Weiß wäre dort ein leuchtender Fleck. Sichtbar wird
 * der Kasten ohnehin erst dort, wo es darauf ankommt - beim Zeigen, wenn die
 * Zeile grau wird, behält die Kurve ihren Grund.
 *
 * Vier Pixel Rundung, wie am Vorschaubild daneben: dieselbe Ausnahme vom
 * `border-radius: 0` der Marke, aus demselben Grund (Arbeitsansicht, kleine
 * Fläche in einer Liste).
 */
.mini-kurve {
  /**
   * **Quadratisch, so gross wie das Vorschaubild** (05.09.2026): 36 x 36 mit
   * derselben Rundung. Beide stehen als erstes in ihrer Zeile und beide sind
   * eine **Abbildung** - zwei verschiedene Masse nebeneinander sehen aus wie
   * ein Fehler, auch wenn jedes fuer sich stimmt.
   *
   * `border-box`, damit die 36 die **ganze** Flaeche sind: Bei `content-box`
   * kaeme der Innenabstand oben drauf, und das Quadrat waere ein Rechteck.
   */
  display: block; box-sizing: border-box;
  width: 40px; height: 40px; padding: 6px 5px;
  background: var(--paper); border-radius: 4px;
  /* **Derselbe Schatten wie an den Statistikkacheln.** Die Kurve steht auf
     `--shade`, und ohne ihn ist ein weisses Quadrat auf grauem Grund ein
     Loch statt einer Flaeche. Die 4 px Rundung sind aelter als der Schatten
     und bleiben: Sie ist an das Vorschaubild daneben gebunden, nicht an
     `--card-radius`. */
  box-shadow: var(--card-shadow);
  /* Ein Pixel: Auf 36 Pixeln Breite ist ein dickerer Strich keine Kurve mehr,
     sondern ein Band - die Bewegung verschwindet in der Staerke. */
  /* Same green as the big curve: it is the same figure in a second size, and
     a curve that changes colour with its size is learned twice. */
  fill: none; stroke: var(--chart); stroke-width: 1;
}
/**
 * **Jede Zahl in dieser Tabelle traegt dieselbe Klasse** (05.09.2026) - die
 * neben der Kurve und die in den Spalten „Bilder" und „Bewertungen".
 *
 * Vorher erbten die beiden Spaltenwerte die Groesse der Zelle; auf dem Telefon
 * ist die 1 rem, oben stand 0,9 rem, und in einer Karte lagen dann drei Zahlen
 * in zwei Groessen untereinander. Eine Zahl, die groesser gesetzt ist, sieht
 * wichtiger aus - hier waere das eine Behauptung ohne Grund.
 */
.anspruch-zahl { font-variant-numeric: tabular-nums; font-weight: 700; font-size: .9rem; }
.anspruch-zahl .tab-unten { font-weight: 400; }

/* „Beansprucht" hat vier Spalten: Eintrag, Member, Bilder, Bewertungen. Die
   Punkte „was fehlt" standen hier und sind am 05.09.2026 weggefallen - sie sind
   die Frage der Redaktion an einen fremden Eintrag, nicht die eines Betriebs an
   seinen eigenen. Die Breiten laesst der Browser rechnen: Name neben Zahlen ist
   der Fall, in dem automatisch besser ist als geraten.

   Die Spalte „Member" (06.09.2026) traegt nur die Pille - kein Rand daneben,
   denn den Abstand zum Namen setzt jetzt die Zelle, nicht die Pille. Sie bleibt
   in einer Zeile: „Member PLUS" ueber zwei Zeilen waere ein Umbruch mitten in
   einer Angabe. */
.bestand-tabelle.tab-karten td.tab-plan { white-space: nowrap; }
.bestand-tabelle.tab-karten td.tab-plan .plan-pille { margin-left: 0; }

/* Der Postausgang hat fuenf eigene Spalten - dieselbe Tabelle, andere Frage. */
.bestand-tabelle[data-art="post"] { table-layout: fixed; }
.bestand-tabelle[data-art="post"] th:nth-child(1) { width: 15%; }  /* Wann */
.bestand-tabelle[data-art="post"] th:nth-child(2) { width: 24%; }  /* An */
.bestand-tabelle[data-art="post"] th:nth-child(3) { width: 15%; }  /* Art */
.bestand-tabelle[data-art="post"] th:nth-child(4) { width: 30%; }  /* Betreff */
.bestand-tabelle[data-art="post"] th:nth-child(5) { width: 16%; }  /* Status */
/**
 * **„nicht verschickt" ohne Streichung** (05.09.2026).
 *
 * Das Schild `[data-status="rejected"]` traegt einen Strich durch den Text -
 * richtig fuer eine abgelehnte Bewertung („das gilt nicht mehr"), falsch im
 * Postausgang: Dort ist es eine **Auskunft** ueber einen Vorgang, kein
 * Urteil ueber einen Inhalt. Ein durchgestrichenes „nicht verschickt" liest
 * sich ausserdem wie das Gegenteil.
 */
.post-offen { background: var(--state-wait-bg); color: var(--state-wait-ink); }
/**
 * **Die Einzelheiten hinter einem Chevron** (05.09.2026).
 *
 * Zwei Fassungen davor: der Grund in der letzten Spalte (vier Zeilen hoch in
 * sechzehn Prozent Breite) und der Grund in einer eigenen Zeile darunter (die
 * Liste doppelt so lang). Jetzt eine Zeile je Mail, und wer mehr will, klappt
 * auf.
 *
 * Der Chevron steht **vor** der Zeit und dreht beim Aufklappen nach unten -
 * dieselbe Bewegung wie an den Gruppen der Navigation. Wo es nichts zu sehen
 * gibt, bleibt die Stelle leer, damit die Spalte flucht.
 */
.post-klapp {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.2rem; height: 1.2rem; margin-right: .35rem; vertical-align: -.2rem;
  padding: 0; border: 0; background: none; color: var(--soft); cursor: pointer;
}
.post-klapp:hover { color: var(--strong); }
.post-klapp:focus-visible { outline: 2px solid var(--strong); outline-offset: 1px; }
.post-klapp .bk-chevron { width: 1rem; height: 1rem; transition: transform .16s; }
.post-klapp[aria-expanded="true"] .bk-chevron { transform: rotate(90deg); color: var(--strong); }
.post-klapp-leer { cursor: default; }
/* **A row with a kept mail is one click.** The subject is the button
   (`.post-betreff`, underlined like every link-button), the rest of the row
   takes the mouse - so the whole row shows the hand and the shade. */
.post-zeile-mail { cursor: pointer; }
.post-zeile-mail:hover td { background: var(--shade); }
.wie-link.post-betreff { max-width: 100%; text-align: left; color: var(--ink); }
.post-zeile-mail:hover .wie-link.post-betreff { text-decoration-thickness: 2px; }
@media (prefers-reduced-motion: reduce) {
  .post-klapp .bk-chevron { transition: none; }
}
/* Die aufgeklappten Einzelheiten: leise, eingerueckt unter ihrer Zeile. */
.post-mehr td {
  padding: .2rem .6rem .6rem 2.15rem; color: var(--soft); font-size: .85rem;
  line-height: 1.5; border-bottom: 1px solid var(--line);
}
.bestand-tabelle tr:has(+ .post-mehr:not([hidden])) td { border-bottom: 0; }
/* No ground of its own: the head row stands on the panel's ground. `--paper`
   matched it in the light, and in the dark it was a darker band on the card. */
.bestand-tabelle th {
  background: none; text-align: left;
  padding: .5rem .6rem; white-space: nowrap;
}
/* Der **Spaltenkopf** traegt die Ueberschrift: fett, mit kraeftigem Strich
   darunter. Er sagt, was in der Spalte steht. */
.bestand-tabelle thead th { font-weight: 700; border-bottom: 2px solid var(--strong); }
/**
 * **Der Zeilenkopf ist keine Ueberschrift** - er ist der Name der Zeile und
 * steht mager wie alles andere darin. Fett gesetzt waere in einer Liste von
 * fuenfzig jede erste Spalte laut, und die Zahlen daneben, wegen derer man die
 * Liste liest, waeren das Leise.
 *
 * Und er bekommt den **duennen** Strich: Der kraeftige gehoert der einen Kante
 * zwischen Kopf und Inhalt. Sonst zieht er sich durch jede Zeile der ersten
 * Spalte auf.
 *
 * **Das war die Grundform der Statistik und ist jetzt die Grundform.** Die drei
 * Regeln standen mit je fuenf aufgezaehlten Arten daneben (`aufrufe`, `seiten`,
 * `suche`, `termine`, `google…`) - fuenfzehn Selektoren, um an einer Tabelle
 * zurueckzunehmen, was die Grundregel zu viel gesetzt hatte. Wer eine sechste
 * Auswertung baute, musste sie an drei Stellen eintragen und merkte am
 * Ergebnis, dass er es vergessen hatte.
 */
.bestand-tabelle tbody th { font-weight: 400; border-bottom: 1px solid var(--line); }
/**
 * **Die Zellen stehen mittig** (04.09.2026) - vorher `vertical-align: top`.
 *
 * Das war richtig, solange eine Zelle zwei Zeilen hoch werden konnte (Name
 * oben, Gemeinde darunter): Dann fluchtet oben, was zusammengehoert. Seit die
 * Zeile **eine** Zeile ist - Bild, Name, Ort und Art in eigenen Spalten -
 * gibt es nichts mehr zu fluchten, und die hoechste Zelle bestimmt die Hoehe:
 * das 36 Pixel hohe Primärbild. Alles andere hing daneben oben und sah aus, als
 * waere es abgesackt.
 */
.bestand-tabelle td {
  padding: .55rem .6rem; border-bottom: 1px solid var(--line); vertical-align: middle;
}
/**
 * **Markiert wird, was zusammengehoert** (05.09.2026).
 *
 * Im Bestand ist das eine Zeile. Im Postausgang sind es zwei - die Mail und
 * der Grund, warum sie nicht rausging -, und die stehen deshalb in einem
 * eigenen `tbody` je Mail. Eine Tabelle darf viele davon haben; genau dafuer
 * gibt es sie.
 *
 * Zwei Regeln statt einer mit `:has`: Der Postausgang haengt die Markierung an
 * die Klammer, der Bestand an die Zeile. Beides ist dasselbe Versprechen -
 * „das hier gehoert zusammen" - nur mit verschiedenen Klammern.
 */
.bestand-tabelle:not([data-art="post"]) tr:hover td,
.bestand-tabelle:not([data-art="post"]) tbody tr:hover th { background: var(--shade); }
.bestand-tabelle[data-art="post"] tbody:hover td { background: var(--shade); }
.bestand-tabelle a { color: var(--strong); }
/**
 * **Das Primärbild vor dem Namen** (04.09.2026) - quadratisch, 36 Pixel.
 *
 * Es ersetzt die Spalte „Bild": Ein Punkt sagte „vorhanden", das Bild sagt es
 * auch - und zusaetzlich, **welches**. Fehlt es, steht eine graue Flaeche
 * derselben Groesse da; die Zeilenhoehe bleibt damit gleich, und die Namen
 * fluchten weiter untereinander.
 *
 * **Runde Ecken, und nur hier.** Der Styleguide sagt `border-radius: 0`, und
 * das gilt fuer alles, was ein Gast sieht. Dies ist die Arbeitsansicht: ein
 * kleines Quadrat in einer Liste, das mit weichen Ecken schneller als Bild und
 * nicht als Zelle gelesen wird. Ausdruecklich so gewuenscht (04.09.2026) -
 * damit es niemand spaeter „gerade zieht", steht der Grund hier.
 */
/**
 * **Die Zelle bleibt eine Zelle** (04.09.2026).
 *
 * Hier stand `display: flex` **am `<td>`** - und damit war es keine
 * Tabellenzelle mehr, sondern ein Flexkasten, der nur zufaellig in einer Zeile
 * steht. Bei `border-collapse: collapse` faellt so eine Zelle aus dem
 * Rahmenmodell: Die Linie unter der Zeile brach ab, und der Grund beim Zeigen
 * lag nur unter dem Rest der Zeile (mit Bild gemeldet).
 *
 * Die Reihe aus Bild und Name liegt jetzt in einem `<div>` **in** der Zelle.
 * Dieselbe Anordnung, und die Tabelle bleibt eine Tabelle.
 */
.tab-name-reihe { display: flex; gap: .6rem; min-width: 0; }

/**
 * **Ein Titel bleibt einzeilig und endet mit Auslassung.**
 *
 * „Villingen-Schwenningen · Café" brach um, die Zeile wurde doppelt so hoch,
 * und in einer Liste von zweihundert sprang damit jede dritte. Eine Tabelle
 * lebt davon, dass die Zeilen gleich hoch sind - der Blick springt sonst.
 *
 * `max-width` an einer Tabellenzelle wirkt im automatischen Tabellenlayout
 * **nicht** (die Zelle richtet sich nach ihrem Inhalt). Deshalb sitzt die
 * Begrenzung an einem Element **in** der Zelle; dort gilt sie. Der ganze Text
 * steht im `title` - abgeschnitten heisst nicht verloren.
 */
.tab-kappen {
  display: block;
  /**
   * **Die Spalte gibt das Mass, nicht eine eigene Zahl** (04.09.2026).
   *
   * Hier stand erst eine Grenze in Pixeln, dann eine in Zeichen (`34ch`).
   * Beide waren Schaetzungen neben einer Spaltenbreite, die der Browser
   * ausrechnete - und wenn die Spalte breiter war als die Schaetzung, stand
   * rechts Luft, war sie schmaler, half die Schaetzung nicht.
   *
   * Seit die Spalten feste Anteile haben, ist die Antwort einfach: **so breit
   * wie die Spalte.** `100%` in einer Zelle mit fester Breite ist genau das,
   * und die Auslassung greift, wo der Titel nicht hineinpasst.
   */
  max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tab-leise .tab-kappen { max-width: 100%; }
.tab-bild {
  flex: none; border-radius: var(--thumb-radius);
  object-fit: cover; display: block; background: var(--shade);
}
/* Das leere Feld traegt das Themenzeichen, wenn die Sache eines hat - dieselbe
   Auskunft wie draussen in der Terminzeile, an derselben Stelle. */
.tab-bild-leer {
  border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
}
.tab-bild-leer .thema-icon { width: 1.15rem; height: 1.15rem; }
/**
 * **Unter der Maus wird hell, was auf `--shade` liegt.**
 *
 * Das leere Vorschauquadrat und die Zustandsmarke tragen beide `--shade` - und
 * genau die Farbe bekommt die Zeile beim Zeigen. Sie verschwanden damit im
 * Augenblick des Zeigens in ihrer eigenen Zeile, also dann, wenn man hinsieht.
 * Auf `--card-ground` heben sie sich umgekehrt ab, ohne eine neue Farbe
 * einzufuehren: Es ist dieselbe Flaeche, auf der die Liste ohnehin liegt.
 */
/**
 * **Was auf `--shade` steht, wird beim Zeigen weiss.**
 *
 * Die Zeile unter der Maus nimmt `--shade`, und alles darin, was denselben
 * Grund traegt, verschwindet darin: das leere Bildfeld, die Zustandsmarke, das
 * **Auswahlfeld** und die Schiene des **Schalters**. Sie tauschen deshalb mit
 * der Zeile den Ton - Papier auf Grau statt Grau auf Grau.
 *
 * **Und der Knopf des Schalters dreht mit:** Er war weiss und lag damit auf
 * einer weissen Schiene. Er nimmt jetzt den Grund der Zeile (`--shade`) - so
 * bleibt der Unterschied zwischen Schiene und Knopf erhalten, nur andersherum.
 * Angeschaltet aendert sich nichts: Dort ist die Schiene dunkelgruen, und
 * Weiss davor ist der Sinn der Sache.
 */
/**
 * **`background-color`, nicht `background`.**
 *
 * Die Kurzform setzt **alle** Hintergrundangaben zurueck - und ein
 * Auswahlfeld traegt seinen Chevron als `background-image`. Mit der Kurzform
 * verschwand der Pfeil, sobald die Maus die Zeile beruehrte: Das Feld sah in
 * Ruhe aus wie eine Auswahl und unter der Hand wie ein Textfeld.
 */
.bestand-tabelle:not([data-art="post"]) tbody tr:hover .tab-bild-leer,
.bestand-tabelle:not([data-art="post"]) tbody tr:hover .konto-status,
.bestand-tabelle:not([data-art="post"]) tbody tr:hover .tab-zustand,
.bestand-tabelle:not([data-art="post"]) tbody tr:hover .tab-schalter:not([aria-checked="true"]),
.bestand-tabelle[data-art="post"] tbody:hover .tab-bild-leer,
.bestand-tabelle[data-art="post"] tbody:hover .konto-status,
.bestand-tabelle[data-art="post"] tbody:hover .tab-zustand,
.bestand-tabelle[data-art="post"] tbody:hover .tab-schalter:not([aria-checked="true"]),
/* The grey pills (date, place, kind) would vanish in the grey of the row -
   they turn white with it. A customer's pill keeps its colour. */
.bestand-tabelle:not([data-art="post"]) tbody tr:hover .tab-pillen .terminzeile-ort:not(.terminzeile-ort-rubrik),
.bestand-tabelle[data-art="post"] tbody:hover .tab-pillen .terminzeile-ort:not(.terminzeile-ort-rubrik),
.bestand-tabelle:not([data-art="post"]) tbody tr:hover .plan-pille[data-plan="member"] {
  background-color: var(--card-ground);
}
.bestand-tabelle:not([data-art="post"]) tbody tr:hover
  .tab-schalter:not([aria-checked="true"])::before,
.bestand-tabelle[data-art="post"] tbody:hover
  .tab-schalter:not([aria-checked="true"])::before {
  background-color: var(--shade);
}
/**
 * **Wo unter dem Namen noch eine Zeile steht, geht das Bild ueber beide.**
 *
 * Der Fall ist die Beitragsliste: Name und Adresse sagen zusammen, **welcher**
 * Beitrag das ist, das Bild sagt, **wie er aussieht**. Stuenden sie
 * untereinander, waere die linke Kante der Zelle zweimal besetzt - oben vom
 * Bild, darunter von einer Schriftzeile, die nicht dazugehoert.
 *
 * **Das Quadrat gibt die Hoehe der Zeile, nicht umgekehrt.** Es ist das
 * hoechste Stueck in der Zelle, also ist die Zeile so hoch wie es - und damit
 * geht es ueber ihre ganze Hoehe, ohne dass es jemand ausrechnen muss.
 *
 * **Es gilt fuer jede Namenszelle**, nicht nur fuer die mit zwei Zeilen: Ein
 * Bild, das im Bestand 36 px misst und in der Beitragsliste 44, waere dieselbe
 * Spalte in zwei Groessen. Wo unter dem Namen nichts steht, bleibt der
 * Textblock einzeilig und steht mittig am Bild - das ist der einzige
 * Unterschied.
 *
 * **Andersherum geht es nicht**, und das ist eine Messung, keine Meinung: Ein
 * Bild, das seine Hoehe aus der Zeile nimmt (`align-self: stretch`) und seine
 * Breite aus dem Verhaeltnis (`aspect-ratio: 1`), ist eine Zirkelrechnung -
 * die Zeilenhoehe kommt aus ihrem hoechsten Kind, das Kind nimmt sein Mass aus
 * dieser Hoehe. Gemessen wurden daraus 1620 px, und die Tabelle rollte
 * waagerecht. Mit fester Breite und gedehnter Hoehe kommt kein Quadrat heraus,
 * sondern 43 auf 29.
 *
 * Der Textblock daneben dehnt sich mit (`align-items: stretch`) und stellt
 * seinen Inhalt mittig - so steht der Name auf der Mitte des Bildes, ob eine
 * Zeile darunter steht oder keine. Beschnitten wird wie ueberall ueber
 * `object-fit: cover`.
 */
.tab-name-reihe { align-items: stretch; }
.tab-name-reihe .tab-bild { width: 2.75rem; height: 2.75rem; align-self: center; }
.tab-name-text { display: flex; flex-direction: column; justify-content: center; min-width: 0; }
/* **Name und Zustandsmarke in einer Zeile des Textblocks.**

   Der Block ist eine **Spalte** (jede Zeile darin eine Auskunft: Name, darunter
   der Mangel). „vorbei" ist aber keine eigene Zeile, sondern eine Aussage
   **ueber den Namen** - also braucht es darin eine Reihe. `flex-shrink: 0` an
   der Marke, damit aus „vorbei" bei einem langen Namen nicht „vor…" wird; das
   Kappen ist Sache der Spanne daneben. */
.tab-kappen-reihe { display: flex; align-items: baseline; gap: .5rem; min-width: 0; }
.tab-kappen-reihe > .konto-status { flex-shrink: 0; }
/* Der Verweis um das Bild traegt keinen Strich - er ist eine Flaeche, kein
   Wort. Die Regel fuer Verweise steht oben; hier ist die Ausnahme, weil das
   Bild selbst der Verweis ist. */
.tab-bild-weg { display: block; line-height: 0; text-decoration: none; }

/* Die zweite Zeile in einer Zelle: Gemeinde, Gattung, ein Grund. Kleiner und
   leiser - sie erklaert die erste, sie steht nicht neben ihr. */
.tab-unten { display: block; color: var(--soft); font-size: .82rem; }
/**
 * **Leise in derselben Zeile** - grau, aber nicht kleiner.
 *
 * „Ort & Art" ist eine Einordnung und keine Aussage: In der Zeile geht es um
 * den Eintrag, die Gemeinde sagt nur, welcher gemeint ist. Grau genuegt dafuer;
 * kleiner gesetzt waere es eine Fussnote in einer Tabellenspalte, und Spalten
 * haben keine Fussnoten.
 *
 * Die Klasse stand am 04.09.2026 einen Abend lang **im Markup, ohne dass es
 * sie im Stylesheet gab** - der Text war schwarz wie der Name daneben, und die
 * Spalte drueckte sich damit nach vorn. Aufgefallen ist es dem Auftraggeber,
 * nicht mir: Eine Klasse, die niemand definiert, ist von aussen nicht von einer
 * zu unterscheiden, die falsch definiert ist.
 */
.tab-leise { color: var(--soft); }
/**
 * **Der Punkt in den vier Spalten** (04.09.2026) - vorher stand dort „ja" oder
 * „fehlt".
 *
 * Die Spaltenueberschrift sagt, um was es geht; die Zelle sagt nur noch **ob**.
 *
 * **Schwarz, beide** (Entscheidung vom selben Abend): gefuellt heisst ja, hohl
 * heisst nein. Erst waren sie gruen und rot - die Zustandsfarben der Marke -,
 * und das war zweimal schwaecher: Die Marke ist schwarz auf weiss, und eine
 * Ampel in einer Arbeitstabelle zieht den Blick auf die Farbe statt auf die
 * Zeile. Der Unterschied liegt jetzt **nur** in der Form, und damit sieht ihn
 * auch, wer Rot und Gruen nicht unterscheidet - vorher trug die Form ihn
 * mit, jetzt traegt sie ihn allein.
 *
 * Das Wort dazu steht verborgen im Markup und im `title`: Eine Form ist so
 * wenig eine Auskunft wie eine Farbe.
 */
.punkt {
  display: inline-block; width: .7rem; height: .7rem; border-radius: 50%;
  border: 2px solid var(--strong); background: none;
  /* Auf der Grundlinie der Zeile, nicht am oberen Rand der Zelle. */
  vertical-align: middle; margin: .15rem 0;
}
.punkt-da { background: var(--strong); }
/* **Die ganze Zeile hebt sich**, nicht eine Zelle: Der Zeilenkopf (`th`) hat
   einen eigenen Grund (weiss, damit er beim seitlichen Rollen traegt) und blieb
   sonst hell, waehrend der Rest dunkelte - eine halb markierte Zeile ist
   schlechter als keine. */
/* Eine vorbei gegangene Veranstaltung bleibt lesbar - sie war ja mal. */
.bestand-tabelle[data-art="termine"] tr.ist-vorbei { color: var(--soft); }

/**
 * **Die Marke „vorbei" steht neben dem Termin, nicht darunter.** Der Abstand
 * haelt sie vom Datum getrennt; `white-space: nowrap` verhindert, dass das Wort
 * bei schmalem Fenster vom Datum wegbricht und allein in einer Zeile steht.
 * Die Zeile ist gedimmt (`.ist-vorbei`), die Pille traegt ihre eigene Farbe -
 * `.konto-status` setzt `color` selbst, sonst verschwaende sie im Grau.
 */
/* ---------------------------------------------------------------------------
   **DER KIPPSCHALTER FÜR DIE STARTSEITE** (10.09.2026)
   ---------------------------------------------------------------------------

   **Die Fläche sagt den Zustand** - grün heißt „steht auf der Startseite",
   grau heißt „nicht". Dieselbe Regel und dasselbe Farbpaar wie am Vorteil
   (`--state-live-bg`), nur die Form ist eine andere: Dort ist es ein Knopf mit
   Play und Pause, hier ein Schalter mit zwei Zuständen und keiner Handlung
   dazwischen.

   **Rund ist eine dokumentierte Ausnahme** von `border-radius: 0` - wie beim
   Vorteilsknopf, und aus demselben Grund: Ein Kippschalter ist die eine Form,
   die jeder Mensch aus jedem Gerät kennt; eckig sähe er aus wie ein Feld, in
   das man tippt.

   **Farbe allein trägt nichts**, deshalb wandert der Knopf: links aus, rechts
   an. Wer keine Farben unterscheidet, sieht die Stellung. Den Namen trägt der
   Schalter selbst (`aria-label`, `role="switch"`), die Spaltenüberschrift sagt
   wovon.

   Er ist **44 px hoch trefbar** ohne Zeigegerät - dieselbe Regel wie an jeder
   Zeilenlinie. */
.tab-schalter {
  --schalter-breite: 2.4rem;
  --schalter-hoehe: 1.3rem;
  display: inline-flex; align-items: center;
  width: var(--schalter-breite); height: var(--schalter-hoehe);
  padding: 0; border: 0; cursor: pointer;
  border-radius: 999px;
  background: var(--line);
  transition: background .12s ease-in-out;
}
.tab-schalter::before {
  content: ""; display: block;
  width: calc(var(--schalter-hoehe) - 4px); height: calc(var(--schalter-hoehe) - 4px);
  margin-left: 2px;
  border-radius: 50%;
  background: var(--paper);
  transition: transform .12s ease-in-out;
}
/* **Der Strichton, nicht der Flächenton**: `--state-live-bg` ist das blasse
   Grün hinter einer Zustandsmarke - auf einer Schiene von 1,3 rem wäre es
   neben Weiß kaum zu sehen. Der dunkle Ton derselben Paarung trägt hier, und
   der weiße Knopf davor sagt den Rest. */
.tab-schalter[aria-checked="true"] { background: var(--state-live-ink); }
.tab-schalter[aria-checked="true"]::before {
  transform: translateX(calc(var(--schalter-breite) - var(--schalter-hoehe)));
}
.tab-schalter:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
.tab-schalter[disabled] { opacity: .5; cursor: default; }
@media (hover: none) {
  /* Der Daumen trifft die Zelle, nicht den Strich. */
  .tab-schalter { min-height: 44px; }
}

/**
 * **Die Marke „vorbei" steht neben dem Namen und schrumpft nicht mit.**
 *
 * Sie sitzt in derselben Reihe wie das Vorschaubild und der Titel
 * (`.tab-name-reihe`, ein Flexkasten) - der Titel gibt nach (`.tab-kappen`
 * kappt mit Auslassung), die Marke nicht: `flex-shrink: 0`, damit aus
 * „vorbei" bei einem langen Namen nicht „vor…" wird. Den Abstand macht die
 * Reihe (`gap`), also braucht sie hier keinen.
 */
.bestand-tabelle[data-art="termine"] .konto-status {
  flex-shrink: 0;
  white-space: nowrap;
  /* A state of the machine: monospace, regular weight, like the pills of the
     editor head. */
  font-family: var(--mono); font-size: .66rem; font-weight: 400; letter-spacing: .04em;
  padding: .1rem .5rem;
}

/**
 * **Meistgesehen: die Spaltenbreiten stehen fest** (05.09.2026).
 *
 * Vorher rechnete der Browser sie aus dem Inhalt aus, und ein einziger langer
 * Name („Naturcamping Weiherhof am Titisee") schob Ort, Art und die beiden
 * Zahlenspalten an den rechten Rand - in einer Rangliste stehen die Zahlen
 * dann nicht mehr untereinander, und genau die will man vergleichen.
 *
 * Dieselbe Antwort wie im Bestand: feste Anteile, und der Titel endet mit
 * einer Auslassung, wo er nicht hineinpasst. Der ganze Text steht im `title` -
 * abgeschnitten heisst nicht verloren.
 */
.bestand-tabelle[data-art="aufrufe"] { table-layout: fixed; }
.bestand-tabelle[data-art="aufrufe"] th:nth-child(1) { width: 34%; }  /* Seite */
.bestand-tabelle[data-art="aufrufe"] th:nth-child(2) { width: 22%; }  /* Ort */
.bestand-tabelle[data-art="aufrufe"] th:nth-child(3) { width: 20%; }  /* Art */
.bestand-tabelle[data-art="aufrufe"] th:nth-child(4),
.bestand-tabelle[data-art="aufrufe"] th:nth-child(5) { width: 12%; }  /* die Zahlen */
/**
 * **Keine Zeile bricht um.** Eine Tabelle lebt davon, dass die Zeilen gleich
 * hoch sind; eine, die umbricht, springt beim Lesen. Die Begrenzung sitzt hier
 * an der Zelle selbst - im festen Tabellenlayout hat sie ihre Breite schon,
 * also wirkt `overflow` an ihr (im automatischen tut es das nicht).
 */
.bestand-tabelle[data-art="aufrufe"] tbody th,
.bestand-tabelle[data-art="aufrufe"] tbody td {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/**
 * ===========================================================================
 * **WAS GOOGLE ZEIGT: drei Tabellen, dieselbe Bauform** (09.09.2026)
 * ===========================================================================
 *
 * Solange die Search Console nichts geliefert hatte, war hier nur der leere
 * Zustand zu sehen. Mit sechzehn Monaten Rueckgriff stehen dreistellige
 * Zeilenzahlen und Adressen von siebzig Zeichen darin - und die Tabellen
 * liefen ohne `data-art`, also mit `table-layout: auto`: Die Adressspalte nahm
 * sich alles, die Zahlenspalten standen auf dem Telefon **hinter dem rechten
 * Rand**. Man rollte seitlich zu der Zahl, wegen der man gekommen war.
 *
 * Dieselbe Antwort wie in „Meistgesehen": feste Anteile, und was nicht
 * hineinpasst, endet mit einer Auslassung - der ganze Wert steht im `title`.
 *
 * **Drei Namen und nicht einer**, weil die drei Tabellen verschiedene Spalten
 * haben; was sie teilen, steht als `^="google"` an einer Stelle.
 */
.bestand-tabelle[data-art^="google"] { table-layout: fixed; }

/* Rankt, gibt es aber nicht mehr: Adresse | Antwort | Gezeigt. */
.bestand-tabelle[data-art="google-adressen"] th:nth-child(1) { width: 58%; }
.bestand-tabelle[data-art="google-adressen"] th:nth-child(2) { width: 22%; }
.bestand-tabelle[data-art="google-adressen"] th:nth-child(3) { width: 20%; }

/**
 * Je Seite: Seite | Ist heute | Gezeigt | Klicks - und **ohne** „Ist heute",
 * solange kein Abgleich gelaufen ist. Die Spaltenzahl steht deshalb an der
 * Tabelle (`data-spalten`) statt geraten zu werden: `nth-child(3)` heisst
 * einmal „Gezeigt" und einmal „Klicks".
 */
.bestand-tabelle[data-art="google-seiten"][data-spalten="4"] th:nth-child(1) { width: 46%; }
.bestand-tabelle[data-art="google-seiten"][data-spalten="4"] th:nth-child(2) { width: 22%; }
.bestand-tabelle[data-art="google-seiten"][data-spalten="4"] th:nth-child(3),
.bestand-tabelle[data-art="google-seiten"][data-spalten="4"] th:nth-child(4) { width: 16%; }
.bestand-tabelle[data-art="google-seiten"][data-spalten="3"] th:nth-child(1) { width: 60%; }
.bestand-tabelle[data-art="google-seiten"][data-spalten="3"] th:nth-child(2),
.bestand-tabelle[data-art="google-seiten"][data-spalten="3"] th:nth-child(3) { width: 20%; }

/* Je Frage: Frage | Gezeigt | Klicks | Platz. */
.bestand-tabelle[data-art="google-fragen"] th:nth-child(1) { width: 52%; }
.bestand-tabelle[data-art="google-fragen"] th:nth-child(2),
.bestand-tabelle[data-art="google-fragen"] th:nth-child(3),
.bestand-tabelle[data-art="google-fragen"] th:nth-child(4) { width: 16%; }

/**
 * **Eine Adresse wird gekappt, eine Frage bricht um.**
 *
 * `/magazin/die-schoensten-wasserfaelle-im-schwarzwald-und-wo-du-sie-findest/`
 * hat keine Stelle, an der ein Umbruch etwas hiesse - vier Zeilen davon in
 * einer Rangliste kosten den Vergleich, und den Rest liest ohnehin niemand.
 * Eine Frage dagegen ist Sprache: Sie bricht um wie der Begriff in „Wonach
 * gesucht wird", denn ihre letzten Woerter sind oft die entscheidenden.
 *
 * Gekappt wird an einem Element **in** der Zelle (`.tab-kappen`, dasselbe
 * Bauteil wie im Bestand): Der Zeilenkopf traegt darunter noch den Befund,
 * und der soll seine eigene Zeile behalten.
 */
.bestand-tabelle[data-art^="google"] tbody th { overflow: hidden; }
.bestand-tabelle[data-art="google-fragen"] tbody th { overflow-wrap: anywhere; }
/**
 * **Keine Zeile bricht um** - dieselbe Regel wie in „Meistgesehen". „Nicht
 * erreicht" auf zwei Zeilen macht jede zweite Zeile doppelt hoch, und in einer
 * Liste, die man von oben nach unten ueberfliegt, springt der Blick dann bei
 * jedem Schritt. Nur die Fragetabelle nimmt sich davon aus: Dort steht in der
 * ersten Spalte Sprache, und die darf umbrechen.
 */
.bestand-tabelle[data-art="google-adressen"] tbody td,
.bestand-tabelle[data-art="google-seiten"] tbody td {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Die zweite Zeile im Zeilenkopf - Weiterleitungsziel und Befund - endet
   ebenfalls mit einer Auslassung statt hart an der Spaltenkante. */
.bestand-tabelle[data-art="google-adressen"] tbody th .tab-unten,
.bestand-tabelle[data-art="google-seiten"] tbody th .tab-unten {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/**
 * **Auf dem Telefon faellt je eine Spalte weg** (46 rem) - dieselbe Frage wie
 * im Bestand: Was ist die Auskunft, mit der man die Liste oeffnet?
 *
 * „Ist heute" beantwortet den Umzug, und den beantwortet die Tabelle darueber
 * schon fuer jede Adresse, an der etwas nicht stimmt. „Platz" ist an den
 * meisten Zeilen ohnehin ein Strich (unter 25 Anzeigen sagt er nichts). Was
 * bleibt, ist die Frage, wegen der man kommt: **welche Seite, wie oft gezeigt,
 * wie oft geklickt.**
 */
@media (max-width: 46rem) {
  .bestand-tabelle[data-art="google-seiten"][data-spalten="4"] th:nth-child(2),
  .bestand-tabelle[data-art="google-seiten"][data-spalten="4"] td:nth-child(2),
  .bestand-tabelle[data-art="google-fragen"] th:nth-child(4),
  .bestand-tabelle[data-art="google-fragen"] td:nth-child(4) { display: none; }
  .bestand-tabelle[data-art="google-seiten"][data-spalten="4"] th:nth-child(1) { width: 52%; }
  .bestand-tabelle[data-art="google-seiten"][data-spalten="4"] th:nth-child(3),
  .bestand-tabelle[data-art="google-seiten"][data-spalten="4"] th:nth-child(4) { width: 24%; }
  .bestand-tabelle[data-art="google-seiten"][data-spalten="3"] th:nth-child(1) { width: 52%; }
  .bestand-tabelle[data-art="google-seiten"][data-spalten="3"] th:nth-child(2),
  .bestand-tabelle[data-art="google-seiten"][data-spalten="3"] th:nth-child(3) { width: 24%; }
  .bestand-tabelle[data-art="google-fragen"] th:nth-child(1) { width: 56%; }
  .bestand-tabelle[data-art="google-fragen"] th:nth-child(2),
  .bestand-tabelle[data-art="google-fragen"] th:nth-child(3) { width: 22%; }
  /* Die Antwort bekommt Platz fuer „weitergeleitet" - sie ist der Befund. */
  .bestand-tabelle[data-art="google-adressen"] th:nth-child(1) { width: 44%; }
  .bestand-tabelle[data-art="google-adressen"] th:nth-child(2) { width: 34%; }
  .bestand-tabelle[data-art="google-adressen"] th:nth-child(3) { width: 22%; }
}

/**
 * **Die Punktspalten stehen mittig** (04.09.2026) - Kopf und Zelle zusammen.
 *
 * Ein Punkt hat keinen Anfang, an dem er sich ausrichten koennte. Links
 * angeschlagen sass er in einer breiten Spalte weit weg von seiner
 * Ueberschrift, und wer die Zeile las, musste den Weg jedes Mal neu suchen.
 * Mittig steht er unter dem Wort, das ihn benennt - und vier Punkte in einer
 * Zeile stehen als vier Antworten da statt als eine Reihe.
 */
/**
 * **Ein Feld und sein Knopf in einer Zelle** (`.tab-tunfeld`, 10.09.2026).
 *
 * Zwei Flaechen schreiben in einer Tabellenzeile: die Quellenliste („was gab
 * der Kanal her") und die Pruefliste („wann wieder nachsehen", „naechster
 * Termin"). Beide brauchen dasselbe - ein Feld, das die Zelle fuellt, und
 * daneben einen Knopf, der nicht schrumpft. Eine Klasse, zwei Leser.
 *
 * Auf dem Telefon (`.tab-karten`) bricht die Zeile um, und der Knopf steht
 * ueber die ganze Breite: Ein Knopf, den man mit dem Daumen trifft, ist eine
 * Zeile hoch.
 */
/**
 * **Das Anlegen steht eingeklappt** - die Handlung dieses Bildschirms ist die
 * Runde, nicht das Eintragen. Dieselbe Bauart wie „Zeiten als Satz": Was den
 * Normalfall verdeckt, kommt hinter eine Klappe. Der Abstand nach unten
 * trennt es von der Reiterleiste, die darunter der eigentliche Anfang ist.
 */
.quellen-neu { margin: 1.2rem 0 1.6rem; }
.quellen-neu summary { cursor: pointer; padding: .3rem 0; }

.tab-tunfeld { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.tab-tunfeld input { flex: 1 1 9rem; min-width: 0; }
.tab-tunfeld .action { flex: none; }
@media (max-width: 46rem) {
  .tab-karten .tab-tunfeld { flex-wrap: wrap; }
  .tab-karten .tab-tunfeld input { flex: 1 1 100%; }
  .tab-karten .tab-tunfeld .action { width: 100%; }
}

.bestand-tabelle th.tab-mitte,
.bestand-tabelle td.tab-mitte { text-align: center; }
/**
 * **Ziffern gleicher Breite in den Zaehlspalten.**
 *
 * Eine Rangliste vergleicht man mit dem Auge: 243.940 ueber 17.304 ueber 9.812
 * liest sich nur dann als Gefaelle, wenn die Ziffern untereinander stehen. In
 * der Proportionalschrift ist eine 1 schmaler als eine 8, und schon bei
 * fuenf Zeilen wandert die Kante. Dieselbe Regel wie in der Herkunftsliste.
 */
.bestand-tabelle td.tab-mitte { font-variant-numeric: tabular-nums; }
/**
 * **Die Optionen nebeneinander, mit einem Mittelpunkt dazwischen**
 * (04.09.2026).
 *
 * Sie standen untereinander, und damit war jede Zeile der Tabelle zwei Zeilen
 * hoch - bei zwanzig Eintraegen ein Bildschirm mehr. Der Mittelpunkt ist der
 * leiseste Trenner, den es gibt: kein Strich, keine Klammer, kein Kasten. Er
 * ist `aria-hidden`, weil eine Vorlesestimme „Punkt" sagen wuerde, wo nichts
 * zu sagen ist.
 */
.tab-tun { white-space: nowrap; }
/**
 * **Die Optionen als Zeichen** - Bearbeiten, Vorschau, Einladen.
 *
 * Die Trefferflaeche ist groesser als das Zeichen (2 rem im Quadrat, ohne
 * Zeigegeraet 2.75): Ein 17er Zeichen ist mit dem Daumen ein Glueckstreffer.
 * Getrennt wird mit Luft und nicht mit einem Punkt - zwischen zwei Zeichen
 * waere er ein drittes.
 */
.tab-zeichen {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.5rem; height: 1.5rem; padding: 0; border: 0; background: none;
  color: var(--soft); cursor: pointer;
}
.tab-zeichen + .tab-zeichen { margin-left: .15rem; }
/* **Der Papierkorb wird rot, wenn man ihn anfasst** - nicht vorher: Eine rote
   Spalte in jeder Zeile ist eine Warnung, die nichts meint. Genommen ist das
   Zustandspaar des Hauses, kein neues Rot. */
.tab-weg:hover, .tab-weg:focus-visible { color: var(--state-stop-ink); }
/**
 * **Beim Zeigen hebt sich das Zeichen heraus** - heller Grund im Quadrat, leicht
 * gerundet.
 *
 * Ohne Flaeche ist das Einzige, was ein Zeigen anzeigt, ein Farbwechsel von
 * `--soft` nach `--strong` - und der ist an einem Strichzeichen von 17 Pixeln
 * kaum zu sehen. Die Flaeche sagt zwei Dinge auf einmal: **hier** wird
 * getroffen (das Ziel ist groesser als das Zeichen) und **das hier** ist
 * gemeint, nicht das Zeichen daneben.
 *
 * `--paper` und nicht Weiss: Die Zeile darunter faerbt sich beim Zeigen nach
 * `--shade`, das Quadrat hebt sich davon ab - und im Dunkelmodus stimmt das
 * Verhaeltnis genauso. Ein festes `#fff` waere dort ein Loch.
 *
 * **Die Rundung ist dieselben 4 px wie an der Infobox** und aus demselben
 * Grund: Sie ist keine Form, sondern eine **Kante, die zurueckweicht** - eine
 * scharfe Ecke mitten in einer Tabellenzelle liest sich als zweiter Kasten in
 * der Zeile. Steht in der Liste der Ausnahmen (Styleguide > Form).
 */
.tab-zeichen:hover, .tab-zeichen:focus-visible {
  color: var(--strong); background: var(--paper); border-radius: 4px;
}
.tab-zeichen:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
@media (hover: none) {
  .tab-zeichen { width: 2.75rem; height: 2.75rem; }
}
.tab-trenn { color: var(--line); margin: 0 .4rem; }
/* **Kleiner als ein Feld im Formular** - das ist die einzige Abweichung, und
   sie hat einen Grund: In einer Zeile von 36 Pixeln Hoehe wuerde ein Feld in
   Formulargroesse die Zeile aufblasen. Rahmen, Ecke, Pfeil und Fokus kommen
   aus der Grundregel. */
.tab-zustand { font-size: .85rem; padding: .15rem 1.7rem .15rem .45rem; min-height: 2rem; }

/* „Neuen Eintrag anlegen" steht **unter** der Tabelle (04.09.2026): Ueber ihr
   steht, was man liest; darunter, was man tut, wenn die Tabelle die Antwort
   nicht hatte. */
/**
 * **Die Suche ueber dem Ganzen** - mit ihrer Vorschlagsliste darunter.
 *
 * Sie schwebt: Die Liste liegt **ueber** der Tabelle, statt sie
 * herunterzuschieben. Eine Liste, die den Inhalt verschiebt, laesst die
 * Tabelle bei jedem Buchstaben springen.
 */
/* **Ohne Hoechstbreite** (04.09.2026): Sie stand bei 32 rem und hoerte mitten
   in der Ansicht auf. Ein Feld, das oben quer steht, gehoert auch quer - und
   die Vorschlagsliste darunter nimmt dieselbe Breite. */
.bestand-suche { position: relative; margin: 0 0 1.2rem; }
/**
 * **Der Bildschnitt: eine eigene Zeile zwischen Reitern und Tabelle.**
 *
 * Er liegt **quer** zu den Reitern - die sagen die Stufe im Ablauf, er sagt,
 * ob der Eintrag draussen ueberhaupt vorkommt. Deshalb steht er nicht in der
 * Reiterleiste: In derselben Zeile passte er auf dem Telefon nicht daneben,
 * und was dort umbricht, liest sich als fuenfter Reiter.
 *
 * Der Abstand nach oben ist knapp und der nach unten weit - so gehoert er
 * sichtbar zu den Reitern darueber und nicht zur Tabelle darunter.
 */
/**
 * **Ein Abstand fuer den Kopf einer Bestandsliste** - Suche, Reiter, Schnitt.
 *
 * Sie standen mit drei Werten uebereinander (1,2 rem, 0,8 rem und -0,2/1,1),
 * weil jede Zeile einzeln entstanden ist: Der eine wollte den Schnitt an die
 * Reiter heranziehen, der andere die Suche absetzen. Uebereinander gelesen
 * ergab das eine Treppe - und drei Abstaende zwischen vier Dingen, von denen
 * keiner eine Aussage macht.
 *
 * **Jetzt einer**, und die Aussage macht die **Reihenfolge**: erst der
 * Ausschnitt (Suche), dann die Stufe (Reiter), dann der Schnitt quer dazu -
 * darunter die Tabelle. Wer eine Zeile dazubaut, bekommt denselben Abstand,
 * ohne ihn zu setzen.
 *
 * Am `>` gebunden, damit `.reiter-leiste` bleibt, was sie im Editor und in den
 * Buechern ist: Dort steht sie in anderen Behaeltern und mit ihrem eigenen Mass.
 */
.bk-tafel > .jahrband,
.bk-tafel > .bestand-suche,
.bk-tafel > .reiter-leiste,
.bk-tafel > .kopfschnitte,
.bk-tafel > .bestand-bild { margin: 0 0 1.1rem; }

/**
 * **Die Tafel: das Papier unter der Arbeit.**
 *
 * Dieselbe Flaeche wie eine Statistikkachel - es gibt im Backend **eine**
 * Sorte Papier, und die Tokens stehen an einer Stelle. Ueberschrift und
 * Vorspann bleiben darueber auf dem Grund; was darunter steht, liegt darauf.
 * Welcher Abschnitt eine bekommt, entscheidet `tafelnBauen()` in `profil.js` -
 * hier steht nur, wie sie aussieht.
 *
 * **Das erste und das letzte Kind verlieren ihren Aussenabstand.** Fast jedes
 * Bauteil hier bringt einen eigenen mit (`.konto-liste` oben, `.tab-fussnote`
 * unten); ohne das haette die Tafel zwei Polster uebereinander, und zwar in
 * jedem Bereich ein anderes.
 */
.bk-tafel {
  background: var(--card-ground);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
  /* **Ringsum dasselbe Mass.** Oben stand 1,25 und an den Seiten 1,4 - ein
     Unterschied, den man einzeln nicht sieht und nebeneinander sofort. Eine
     Tafel hat vier Kanten und einen Rand. */
  padding: 1.4rem;
}
/* Was oben und unten in der Tafel steht, bringt seinen eigenen Aussenabstand
   mit - sonst laegen zwei Polster uebereinander, und zwar in jedem Panel ein
   anderes. Dieselbe Regel wie an `.bk-tafel`. */
.ed-block > :first-child,
.ed-bilder > :first-child,
.ed-vorteile > :first-child { margin-top: 0; }
.ed-block > :last-child,
.ed-bilder > :last-child,
.ed-vorteile > :last-child { margin-bottom: 0; }
.bk-tafel > :first-child { margin-top: 0; }
.bk-tafel > :last-child { margin-bottom: 0; }
/* Zwei Blaetter untereinander brauchen den Abstand, den ein Blatt zum
   naechsten haelt - dasselbe Mass wie das Polster darin. */
.bk-tafel + .bk-tafel { margin-top: 1.4rem; }
/* **Ein leeres Blatt ist kein Blatt.** Eine mitgebrachte Tafel steht im
   Dokument, bevor sie etwas traegt - und in den zwei Ausstiegen unter
   `#/google` (nie gelaufen, kein Zeitraum) traegt sie nie etwas. Ein weisser
   Kasten ohne Inhalt sieht aus, als fehle etwas. */
.bk-tafel:empty { display: none; }

/**
 * **Das Jahresband ueber der Terminliste** - zwoelf Monate, drei zurueck und
 * neun nach vorn. Warum das Fenster rollt und was es beantwortet, steht bei
 * `malJahrband` in `profil.js`.
 *
 * **Zwoelf gleiche Spalten, nicht `auto-fit`.** Das Fenster hat zwoelf Monate,
 * und zwoelf ist hier keine Menge, die sich aus dem Bestand ergibt - eine
 * Spalte, die je nach Breite umbricht, waere kein Fenster mehr.
 *
 * **Keine eigene Breite.** Suchfeld, Reiterleiste und Tabelle darunter gehen
 * auf die volle Breite des Bereichs; ein Band, das bei 58 rem endete, saesse
 * als Absatz ueber ihnen und riesse eine Stufe, die nichts bedeutet.
 */
.jahr-kopf {
  margin: 0 0 .4rem; color: var(--soft); font-size: .9rem;
  font-variant-numeric: tabular-nums;
}
.jahr-kopf strong { color: var(--strong); }
.jahr-kopf .wie-link { margin-left: .4rem; font-size: .85rem; }
.jahr-zellen {
  display: grid; grid-template-columns: repeat(12, 1fr);
  border: 1px solid var(--line);
}
/**
 * **Jede Zelle ist ein Knopf** - der Klick schneidet die Tabelle darunter auf
 * diesen Monat. Sie erbt nichts von `button`: eigene Schrift, kein Rahmen,
 * kein Grund - den setzt die Ampel.
 */
/**
 * **Das Feld ist der Bezug, der Knopf fuellt es aus.**
 *
 * Die Schicht mit den Verweisen haengt an der Zelle und darf nicht in ihr
 * liegen (ein Verweis in einem Knopf ist ungueltig). Also ist das Rasterkind
 * ein `div`, und der Knopf nimmt sich die ganze Flaeche darin.
 */
.jahr-feld { position: relative; display: flex; min-width: 0; }
.jahr-zelle {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: .1rem;
  padding: .45rem .3rem .5rem; border: 0; border-left: 1px solid var(--line);
  background: none; font: inherit; cursor: pointer; position: relative;
}
.jahr-feld:first-child .jahr-zelle { border-left: 0; }
.jahr-monat { color: var(--soft); font-size: .76rem; }
/* Tabellenziffern, damit die zwoelf Zahlen auf einer Achse stehen - dieselbe
   Regel wie an der Reiterzahl. */
.jahr-zahl {
  color: var(--strong); font-size: 1.05rem; font-variant-numeric: tabular-nums;
}
/* **Die Null ist die Nachricht**, also steht sie da - eine leere Zelle laese
   sich als „noch nicht geladen". */
.jahr-zahl-null { color: var(--soft); }

/**
 * **Die Ampel: fuenf Stufen aus drei Zustandspaaren des Hauses.**
 *
 * `--state-stop` (leer), `--state-wait` (unter dem Ziel), `--state-live` (am
 * Ziel) - dieselben Token, die eine Zustandspille traegt, und es gibt sie hell
 * wie dunkel. **Kein neues Rot und keine Rubrikfarbe:** Farbe gehoert im Haus
 * den vier Rubriken, die drei Zustandspaare sind die dokumentierte Ausnahme
 * davon.
 *
 * **Die zwei Zwischentoene sind gerechnet, nicht getippt** (`color-mix`) - und
 * zwar in **beide** Richtungen aus demselben Paar: `wenig` liegt zur
 * Papierfarbe hin, `voll` zur Schriftfarbe hin. Damit stimmt die Richtung in
 * hell **und** dunkel von selbst: Im Dunkeln ist `--paper` dunkel und
 * `--…-ink` hell, also wird `wenig` leiser und `voll` lauter, genau wie im
 * Hellen. Zwei abgetippte Hexwerte muessten dafuer je Modus einzeln gesetzt und
 * geprueft werden.
 *
 * **Die Farbe ist der zweite Traeger.** Die Zahl steht in der Zelle, und der
 * Satz unter dem Band nennt die leeren Monate im Klartext - wer die Farben
 * nicht unterscheidet, verliert nichts. Deshalb duerfen die fuenf Stufen auch
 * dicht beieinander liegen: Sie sind eine Ahnung, keine Auskunft.
 */
.jahr-leer  { background: var(--state-stop-bg); }
.jahr-wenig { background: color-mix(in srgb, var(--state-wait-bg) 45%, var(--paper)); }
.jahr-fast  { background: var(--state-wait-bg); }
.jahr-gut   { background: var(--state-live-bg); }
.jahr-voll  { background: color-mix(in srgb, var(--state-live-ink) 25%, var(--state-live-bg)); }
.jahr-leer  .jahr-monat, .jahr-leer  .jahr-zahl { color: var(--state-stop-ink); }
.jahr-wenig .jahr-monat, .jahr-wenig .jahr-zahl,
.jahr-fast  .jahr-monat, .jahr-fast  .jahr-zahl { color: var(--state-wait-ink); }
.jahr-gut   .jahr-monat, .jahr-gut   .jahr-zahl,
.jahr-voll  .jahr-monat, .jahr-voll  .jahr-zahl { color: var(--state-live-ink); }

/**
 * **Drei Aussagen, drei Formen** - keine davon liegt auf der Flaeche, denn die
 * gehoert der Ampel: **jetzt** ist ein Strich oben, **gewaehlt** ein Rahmen
 * ringsum, **Jahreswechsel** eine kraeftigere Linie zwischen zwei Zellen.
 */
/**
 * **Die drei Namen in der Zelle.**
 *
 * Sie stehen linksbuendig unter der Zahl - eine Liste liest man an ihrer
 * linken Kante, und die Zahl darueber ist die Ueberschrift dazu. Jeder Name
 * wird **gekuerzt, nie umgebrochen**: Bei rund 84 px Spaltenbreite ergaebe ein
 * Umbruch drei Zeilen fuer einen Namen, und aus der Reihe wuerde eine zweite
 * Tabelle. Dass da mehr steht, sagen die Auslassungspunkte - und was da steht,
 * die Schicht.
 */
.jahr-liste {
  display: flex; flex-direction: column; gap: .05rem;
  width: 100%; min-width: 0; margin-top: .25rem; text-align: left;
}
.jahr-zeile { display: flex; gap: .25rem; min-width: 0; font-size: .72rem; }
.jahr-tag { flex: none; font-variant-numeric: tabular-nums; opacity: .75; }
.jahr-name {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* **Ein Entwurf steht gestrichelt da** - dieselbe Aussage wie die Zustandswahl
   in seiner Zeile, nur als Form. Farbe ist hier von der Ampel belegt. */
.jahr-entwurf { text-decoration: underline dashed; text-underline-offset: 2px; }
/* Die vierte Zeile ist eine Zahl und kein Name - also leiser und ohne Tag. */
.jahr-mehr { font-size: .7rem; opacity: .75; }

/**
 * **Die Schicht: alle Termine des Monats, als Verweise.**
 *
 * Sie kommt beim Zeigen und im Fokus hervor. **Beides**, nicht nur das Zeigen:
 * Wer die Zellen mit den Pfeiltasten durchgeht, bekommt dieselbe Liste, und
 * die Tabulatortaste fuehrt hinein. Einen Finger gibt es hier nicht - unter
 * 34 rem sind die Zellen weg.
 *
 * Schwarzer Rahmen wie jede Schicht des Hauses, Papier der Arbeitsflaeche, und
 * sie liegt ueber der Tabelle (`z-index`). Laenger als 18 rem rollt sie.
 */
.jahr-schicht {
  display: none; position: absolute; top: calc(100% + 1px); left: -1px; z-index: 30;
  min-width: 20rem; max-width: 26rem; max-height: 18rem; overflow-y: auto;
  padding: .5rem; text-align: left;
  background: var(--card-ground); border: 1px solid var(--strong);
  box-shadow: var(--card-shadow);
}
.jahr-feld:hover .jahr-schicht,
.jahr-feld:focus-within .jahr-schicht { display: block; }
/* **Die letzten fuenf Spalten haengen rechts** - links gestellt liefe die
   Schicht aus dem Blatt heraus, und eine Liste mit einem Rollbalken quer ist
   keine. */
.jahr-feld:nth-child(n+8) .jahr-schicht { left: auto; right: -1px; }
.jahr-schicht-kopf {
  margin: 0 0 .3rem; font-size: .72rem; color: var(--soft);
  font-variant-numeric: tabular-nums;
}
/* **So klein wie in der Zelle** (.72rem): Die Schicht ist dieselbe Liste,
   nur vollstaendig - zwei Schriftgroessen fuer dieselbe Sache lesen sich als
   zwei Bauteile. Und sie zeigt bei sechzehn Terminen mehr, bevor sie rollt. */
.jahr-schicht a {
  display: flex; align-items: baseline; gap: .4rem;
  padding: .2rem .3rem; color: var(--ink); text-decoration: none;
  font-size: .72rem; line-height: 1.35;
}
.jahr-schicht a:hover,
.jahr-schicht a:focus-visible { background: var(--shade); color: var(--strong); }
/**
 * **Eine Zeile je Termin, gekuerzt statt umgebrochen.**
 *
 * Die Schicht ist eine **Liste**, und eine Liste zaehlt man an ihren Zeilen:
 * Ein Name, der in vier Zeilen umbricht, sieht aus wie vier Termine. Bei
 * sechzehn Terminen entschied damit die Laenge der Namen, wie viel man ohne
 * Rollen sieht. Gekuerzt steht jeder Termin auf derselben Hoehe, und die
 * Auslassungspunkte sagen, dass der Name weitergeht - den ganzen nennt der
 * `title` der Zeile, und dahinter liegt ohnehin der Editor.
 *
 * `flex: 1` gehoert dazu: Ohne das nahm sich die Marke „Entwurf" ihre Breite
 * aus der Mitte der Zeile, und der Name bekam den Rest.
 */
.jahr-schicht-name {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/**
 * **Die Marke folgt der Zeile, in der sie steht** - .65rem statt .8rem und
 * ein engeres Polster: Auf einer Zeile von .72rem war sie der lauteste Teil,
 * und sie ist die Nebenbemerkung.
 *
 * **Beim Zeigen wird sie weiss.** Ihr Grund ist `--shade` und der der Zeile
 * beim Zeigen ebenfalls - sie verschwand darin. Dasselbe Papier wie die
 * Schicht bringt sie zurueck; dieselbe Loesung wie an den Zeilen der
 * Bestandstabellen.
 */
/* Monospace und normal geschnitten: In der Liste ist „Entwurf" eine **Marke
   am Rand**, kein Wort im Satz. Fett gehoert dem Namen daneben, und die
   Monospace sagt „Zustand", wie jede andere Systemangabe des Hauses. */
.jahr-schicht .konto-status {
  flex: none; font-size: .65rem; padding: .1rem .45rem;
  font-family: var(--mono); font-weight: 400;
}
.jahr-schicht a:hover .konto-status,
.jahr-schicht a:focus-visible .konto-status { background: var(--card-ground); }

.jahr-jetzt { box-shadow: inset 0 3px 0 var(--strong); }
.jahr-neuesjahr { border-left: 2px solid var(--strong); }
.jahr-zelle:hover { outline: 1px solid var(--strong); outline-offset: -1px; }
.jahr-zelle:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
.jahr-zelle[aria-pressed="true"] {
  outline: 2px solid var(--strong); outline-offset: -2px;
}
/**
 * **Der Satz ist die zugaengliche Fassung des Bandes.** Am Schirm steht er
 * unsichtbar dahinter (dieselben Werte wie `.visually-hidden`, nicht
 * `display: none` - das naehme ihn auch aus dem Vorlesebaum), unter 34 rem
 * tritt er an die Stelle der Zellen.
 */
.jahr-satz {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
/**
 * **Unter 34 rem bleibt der Kopf und geht die Reihe.** Zwoelf Zellen auf
 * 390 px sind 30 px je Zelle. Der Kopf bleibt, weil in ihm der gewaehlte Monat
 * und sein Rueckweg stehen - ohne ihn haenge ein am Schirm gesetzter Schnitt
 * auf dem Telefon fest.
 */
@media (max-width: 34rem) {
  .jahr-zellen { display: none; }
  .jahr-satz {
    position: static; width: auto; height: auto; margin: 0; padding: 0;
    overflow: visible; clip-path: none; white-space: normal;
    font-size: .9rem; color: var(--soft);
  }
  .jahr-kopf { margin-bottom: .15rem; }
}
/* Der Satz unter der Wahlreihe gehoert zu ihr und nicht zur naechsten Zeile -
   er ruecht deshalb dicht heran, und den Abstand nach unten traegt die Zeile. */
.bestand-rubrik .feld-hint,
.bestand-bild .feld-hint { margin: .35rem 0 0; }

/**
 * **Das Wort vor einer Bahn.**
 *
 * Zwei Bahnen nebeneinander lasen sich als eine Leiste mit acht Feldern, von
 * denen zwei „Alle" hiessen und Verschiedenes meinten. Das Wort macht daraus
 * sichtbar zwei Fragen - klein, grau und in der Monospace wie jede andere
 * Beschriftung, die kein Inhalt ist, sondern sagt, **wonach** hier gefragt
 * wird.
 *
 * Es steht **daneben und nicht darueber**: Eine Zeile mit drei Bahnen
 * uebereinander waere drei Zeilen hoch, und die Reihe ist die Stelle, an der
 * die Tabelle beginnt.
 */
/**
 * **Der Satz ueber der Tabelle: was man gerade sieht.**
 *
 * Fuenf Achsen stehen in drei Zeilen darueber; hier stehen sie in einer. Die
 * **Menge** traegt die Schriftfarbe, die Schnitte dahinter sind leise - die
 * Zahl ist die Auskunft, die Schnitte sind ihr Weg. Der Rueckweg steht nur da,
 * wenn es einen gibt.
 *
 * Er liegt zwischen Bahnen und Tabelle, also dort, wo der Blick ohnehin
 * hinwandert, und traegt den Abstand nach unten zur ersten Zeile.
 */
.schnitt-satz {
  margin: .9rem 0 .5rem; font-size: .88rem; color: var(--soft);
  font-variant-numeric: tabular-nums;
}
.schnitt-satz:empty { display: none; }
.schnitt-satz-menge { color: var(--strong); font-weight: 700; }
.schnitt-satz .wie-link { margin-left: .5rem; font-size: .85rem; }

.schnitt { display: flex; align-items: center; gap: .5rem; min-width: 0; }

.schnitt-wort {
  font-family: var(--mono); font-size: .72rem; color: var(--soft);
  white-space: nowrap;
}
/* Unter 38 rem faellt die Bahn selbst auf die gewoehnliche Wahlreihe zurueck
   (sie bricht um) - dann gehoert das Wort ueber sie, sonst stuende es neben
   einem zweizeiligen Block. */
@media (max-width: 38rem) {
  .schnitt { flex-direction: column; align-items: flex-start; gap: .2rem; }
}
/**
 * **Both cuts in one row** - category on the left, photo on the right. They
 * both lie **across** the tabs: the tabs are the stage in the workflow, the
 * category and the photo cut through it. Side by side is how they read.
 *
 * `align-items: flex-start`, not the `center` that `.schnittreihe` brings:
 * the left block grows downward - a line of text under its rail, and a second
 * rail as soon as a category is chosen. Centred, the photo cut would drift
 * down every time that happens, and the one thing that must not move is the
 * control you are about to use next.
 *
 * **Written as `.schnittreihe.kopfschnitte` on purpose.** With one class it
 * ties with `.schnittreihe` on specificity, and that rule stands further down
 * the file - so the `center` won, and the photo cut sank half a rail. Two
 * classes settle it by weight instead of by line number.
 *
 * It wraps as soon as it gets tight (`.schnittreihe` already does) - then the
 * photo stands under the category again instead of squeezing both.
 */
.schnittreihe.kopfschnitte { align-items: flex-start; }
/**
 * **The second rail, one level deeper** - the genera of the chosen category.
 * It sits under the first, close enough to belong to it and far enough not to
 * touch. Empty it takes no room at all: no category chosen, no rail, and a
 * gap where nothing is would look like something failed to load.
 *
 * It carries no form of its own: **same rail, same size** as the row above.
 * The frontend learned that one the hard way (see `.pills`) - a smaller
 * second row reads as a different component, not as a refinement. That it
 * belongs upward is said by its position and by the fact that it is only
 * there when something above is chosen. The narrow fallback above catches it
 * too, because it is a `.wahlreihe.schalter` inside `.bestand-rubrik`.
 */
/**
 * **Die Bahn haelt ihren Platz frei.**
 *
 * Es gibt sie nur mit gewaehlter Rubrik. Ohne feste Hoehe sprang die ganze
 * Tabelle beim Waehlen um 40 px nach unten und beim Abwaehlen zurueck - und
 * zwar genau in dem Moment, in dem man auf die Zahlen sieht, die sich gerade
 * geaendert haben. `min-height` ist die Hoehe einer Bahn plus ihr Abstand;
 * leer steht dort nichts, der Platz bleibt.
 *
 * Deshalb **kein** `:empty { display: none }`: Das war die Regel, die den
 * Sprung gemacht hat.
 */
.gattungsbahn { margin-top: .4rem; min-height: 2.5rem; }
.kopfschnitte > .bestand-rubrik,
.kopfschnitte > .bestand-bild { margin: 0; }
/**
 * **The genus rail does not push the photo cut aside.** The category block
 * dissolves into the row (`display: contents`), so its rail, the photo cut,
 * the genus rail and the sentence are items of one wrapping row: category and
 * photo side by side, the genus rail and the sentence each on a line of their
 * own below (`order`, full basis). As a block, the category cut took the width
 * of its widest child - the genus rail with nine fields - and the photo cut
 * stood behind it at the far right. Tight, the photo wraps under the category
 * before the genus rail, without a breakpoint.
 */
.kopfschnitte > .bestand-rubrik { display: contents; }
.kopfschnitte > .bestand-rubrik > .schnitt { order: 1; }
.kopfschnitte > .bestand-bild { order: 2; }
.kopfschnitte > .bestand-rubrik > .gattungsbahn { order: 3; flex-basis: 100%; margin-top: -.2rem; }
.kopfschnitte > .bestand-rubrik > .feld-hint { order: 4; flex-basis: 100%; margin: 0; }
.kopfschnitte > .bestand-rubrik > .feld-hint:empty { display: none; }
/**
 * ===========================================================================
 * **The category rail breaks into a row of choices when it does not fit**
 * ===========================================================================
 *
 * `.wahlreihe.schalter` does not wrap and does not scroll - `flex-wrap:
 * nowrap` with `overflow: hidden`, and every field `white-space: nowrap`.
 * That is right for it: the clipping is what gives the chosen end field its
 * round edge. With five fields it also means that on a phone the last one is
 * **cut off and unreachable**, with nothing on screen to say it is there.
 *
 * Measured in the browser: the category rail runs 488 px, the widest genus
 * rail ("Erleben", six fields) 523 px. A 390 px screen offers about 358.
 * No wording saves that.
 *
 * So below the breakpoint both rails fall back to the plain `.wahlreihe` the
 * house already has - same markup, same radios, same numbers, wrapped over
 * two rows. **This is a deliberate step away from the rule** that five pills
 * read as five actions (see the style guide, "Die Bauteile der Hülle"): at
 * 358 px the alternative is not one rail, it is one rail with an invisible
 * field. A choice nobody can reach is worse than a choice that looks like
 * five.
 *
 * **38 rem, and it is the measurement that says so.** 34 rem leaves about
 * 512 px of content, and the 523 px rail clips there - eleven pixels, and
 * the last genus would be gone. 38 rem leaves about 576. **One breakpoint
 * for both rails**, set by the wider of the two: the same component changing
 * shape at two different widths would read as something broken.
 *
 * The photo cut keeps its rail at every width - three fields fit.
 * =========================================================================== */
@media (max-width: 38rem) {
  .bestand-rubrik .wahlreihe.schalter {
    display: flex; flex-wrap: wrap; gap: .4rem;
    width: 100%; border: 0; border-radius: 0; overflow: visible;
  }
  .bestand-rubrik .wahlreihe.schalter .wahl,
  .bestand-rubrik .wahlreihe.schalter .wahl:first-child {
    border: 1px solid var(--line);
  }
  .bestand-rubrik .wahlreihe.schalter .wahl:has(input:checked) {
    border-color: var(--strong);
  }
  .bestand-rubrik .wahlreihe.schalter:has(input:focus-visible) { outline: none; }
  .bestand-rubrik .wahlreihe.schalter .wahl:has(input:focus-visible) {
    outline: 2px solid var(--strong); outline-offset: 2px;
  }
}
/**
 * **Zwei Schnitte in einer Zeile** - der Bildschalter links, der Entwurfsregler
 * rechts daneben. Beide liegen **quer** zur Zeitachse der Reiter, also stehen
 * sie nebeneinander und nicht untereinander: Zwei Zeilen wuerden eine Rangfolge
 * behaupten, die es zwischen ihnen nicht gibt.
 *
 * `flex-wrap`, weil der Regler auf dem Telefon nicht neben den drei Feldern des
 * Schalters herpasst - dann rutscht er darunter, statt beide zu quetschen.
 */
.schnittreihe {
  display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1rem;
}

.bestand-suche .konto-treffer {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 5;
  background: var(--paper); box-shadow: 0 6px 18px rgb(0 0 0 / 12%);
  margin: .2rem 0 0; max-height: 22rem; overflow: auto;
}
/* A suggestion carries its facts in one line: name, place, tier, status -
   centred, so the two pills sit on the middle of the name. */
.bestand-suche .konto-treffer button {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
}
/* `.konto-treffer span` greys every span; the tier pill keeps its own ink. */
.bestand-suche .konto-treffer .plan-pille[data-plan="plus"] { color: var(--strong); }
.bestand-suche .konto-treffer .plan-pille[data-plan="pro"] { color: var(--paper); }
.bestand-suche .konto-treffer button:hover,
.bestand-suche .konto-treffer .treffer-an { background: var(--shade); }
.bestand-suche .konto-treffer button:focus-visible {
  outline: 2px solid var(--strong); outline-offset: -2px;
}

/**
 * **Der schwebende Knopf: ein Plus im Kreis, unten rechts.**
 *
 * Er stand als Zeile **unter** der Tabelle, mit der Begruendung „ueber ihr
 * steht, was man liest; darunter, was man tut". Das galt, solange die Tabelle
 * auf den Bildschirm passte - bei 226 Zeilen liegt „darunter" zweihundert
 * Zeilen tief, und der Weg zum Anlegen fuehrte durch den ganzen Bestand.
 *
 * **Die runde Form ist keine neue Ausnahme**, sondern dieselbe wie das Plus
 * auf der Zeilenlinie (`.linieplus`): Ein Quadrat unten rechts laese sich als
 * abgeschnittene Flaeche, ein Kreis liegt auf der Seite, ohne zu ihr zu
 * gehoeren - und genau das tut er.
 *
 * **`fixed` und in der Ecke des Fensters**, nicht des Inhalts: Er gehoert zu
 * keiner Zeile und zu keiner Tafel. Den Schatten hat er aus demselben Grund
 * wie eine Kachel - er liegt oben.
 */
.bk-plus {
  position: fixed; right: 1.6rem; bottom: 1.6rem; z-index: 25;
  width: 3.4rem; height: 3.4rem; border-radius: 50%;
  display: grid; place-items: center;
  border: 0; padding: 0; cursor: pointer;
  background: var(--strong); color: var(--paper);
  box-shadow: var(--card-shadow);
}
.bk-plus svg { width: 1.5rem; height: 1.5rem; display: block; }
/* Beim Zeigen nur ein wenig heller - eine Bewegung braucht ein Knopf nicht,
   der ohnehin an derselben Stelle liegt. */
.bk-plus:hover { background: color-mix(in srgb, var(--strong) 85%, var(--paper)); }
.bk-plus:focus-visible { outline: 2px solid var(--strong); outline-offset: 3px; }
/* Auf dem Telefon sitzt links unten nichts, rechts unten aber der Daumen -
   naeher an die Ecke, damit er ohne Umgreifen zu treffen ist. */
@media (max-width: 55.99rem) {
  .bk-plus { right: 1rem; bottom: 1rem; }
}

/* ===========================================================================
   DAS GRUNDGERUEST EINER SCHICHT - das X sitzt immer oben rechts
   ===========================================================================

   **Eine Huelle fuer jede Schicht** (04.09.2026). Vorher hatte jede ihren
   eigenen Ausgang: die Galerie ein Quadrat oben rechts, der Ausschnittwaehler
   einen Knopf im Fuss, die Bilderschicht ein „Abbrechen" daneben. Drei Wege
   aus drei Schichten - und keiner dort, wo man ihn sucht. Jetzt ist es
   **immer** das Quadrat oben rechts, dasselbe wie in der Galerie
   (`.backsquare`).

   Der Rahmen ist schwarz und die Kante gerade (Styleguide: `border-radius: 0`).
   Scrollen darf die Schicht und nur sie - `max-height` und `overflow` liegen
   hier, nicht am Inhalt: Sonst scrollt die Seite dahinter mit, und man verliert
   die Stelle, an der man war. */
.schicht {
  position: relative;
  border: 1px solid var(--strong); border-radius: 0; padding: 0;
  width: min(34rem, 94vw); max-height: 90vh; overflow: auto;
  background: var(--paper); color: var(--ink);
}
.schicht::backdrop { background: rgb(0 0 0 / .55); }
/* **In dark mode no layer wears a white frame.** The frame is `--strong` -
   black on paper in the light, and in the dark that is white: a bright line
   around every layer, the one thing on the screen that shone. There the frame
   is the hairline of the house (`--line`), which still parts the layer from
   the page. Every layer of the house: the scaffold (`.schicht`), the consent
   question, the language layer. */
:root[data-theme="dark"] .schicht,
:root[data-theme="dark"] .consent,
:root[data-theme="dark"] .langlayer {
  border-color: var(--line);
}
.schicht-inhalt { padding: 1.4rem; }
/* Das X klebt an der Ecke der Schicht, nicht am Inhalt - es bleibt stehen,
   auch wenn darin gescrollt wird.

   **Dieselbe Groesse wie in der Galerie** (05.09.2026): Es war 2,75 rem gegen
   3,7 rem, mit der Begruendung „dort liegt es auf einem Bild, hier neben einer
   Ueberschrift". Das war eine Unterscheidung ohne Unterschied - es ist derselbe
   Ausgang aus derselben Art Flaeche, und zwei Groessen fuer dasselbe Zeichen
   sind zwei Groessen zu pflegen. Die Masse kommen jetzt aus `.backsquare`. */
.schicht-zu { position: sticky; top: 0; float: right; z-index: 2; }
/* Auch das Zeichen darin ist dasselbe Mass wie in der Galerie (1,15 rem): Der
   Knopf allein reicht nicht - ein kleineres Kreuz in gleich grosser Flaeche
   sieht aus wie ein anderer Knopf. */
.schicht-zu .nav-icon { width: 1.15rem; height: 1.15rem; }

/**
 * **Die Kopfzeile einer Schicht** (05.09.2026) - links der Name, rechts das X.
 *
 * Sie gibt es nur, wo eine Schicht sie bestellt (`schicht({ kopf: true })`);
 * die Bilderschicht und die Rueckfragen bleiben, wie sie waren.
 *
 * **Nur der Inhalt rollt.** Das ist der ganze Zweck: Bei einem langen Text
 * wanderte das X mit nach oben aus dem Bild - der Ausgang verschwand genau
 * dann, wenn man ihn suchte. Deshalb wird die Schicht zur Spalte (`flex`), die
 * Kopfzeile bleibt stehen, und `overflow` wandert von der Schicht in den
 * Inhalt.
 */
/**
 * **Nur die offene Schicht ist eine Spalte.**
 *
 * Hier stand `.schicht:has(.schicht-kopf) { display: flex }` - ohne `[open]`.
 * Das ueberschrieb die Regel des Browsers (`dialog:not([open]) { display: none }`),
 * und der Hilfetext stand danach **unter dem Fuss der Seite**, sichtbar und
 * ungefragt. Ein Fehler mit Ansage: Wer bei einem `dialog` `display` setzt,
 * muss den Zustand mitschreiben.
 */
.schicht[open]:has(.schicht-kopf) { display: flex; flex-direction: column; overflow: hidden; }
.schicht:has(.schicht-kopf) .schicht-inhalt { overflow-y: auto; }
.schicht-kopf {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  flex: none; border-bottom: 1px solid var(--line);
  /* Alle vier Seiten, nicht nur links: Die Kopfzeile der Seite bringt einen
     eigenen oberen Abstand mit, und das X saesse damit vier Pixel unter der
     Ecke, in der es stehen soll. */
  padding: 0 0 0 1.4rem;
  /* **Und kein Abstand nach unten** (06.09.2026): `header { margin-bottom:
     1.6rem }` weiter oben gilt der Kopfzeile der **Seite**, wo sie den Text
     vom Menue abhebt. Hier erbt sie ein `<header>`, das eine Trennlinie hat -
     die Linie trennt schon, der Abstand darunter war nur Luft zwischen ihr
     und dem ersten Wort. Dieselbe Zuruecknahme wie bei `> *` darunter. */
  margin: 0;
}
/**
 * **Die Kopfzeile der Seite gilt hier nicht.**
 *
 * Weiter oben steht `header > * { max-width: var(--rahmen-breite); margin-inline: auto;
 * padding: 0 1.25rem }` - die Regel, die den Inhalt der **Seiten**-Kopfzeile
 * mittig haelt. Ein `<header>` in einer Schicht erbt sie: Das X bekam damit
 * `margin-inline: auto` und stand mitten in der Zeile statt in der Ecke.
 *
 * Deshalb hier zuruecknehmen, statt die globale Regel zu verengen: Sie gilt
 * fuer die Seite, und das soll sie weiter tun.
 */
.schicht-kopf > * { max-width: none; margin-inline: 0; padding: 0; }
/* Der Name steht in der Zeile, nicht darin verschoben: Die Hoehe gibt das
   Quadrat rechts vor (2,75 rem), der Text richtet sich danach. */
.schicht-kopf-wort {
  margin: 0; font-weight: 700; font-size: 1.45rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* In der Kopfzeile klebt das X nicht mehr an der Ecke - es **ist** die Ecke. */
.schicht-kopf .schicht-zu { position: static; float: none; flex: none; }

/* ===========================================================================
   DIE BILDERSCHICHT - am Eintrag, ueber dem Ort
   ===========================================================================

   Dieselbe Form wie der Ausschnittwaehler darunter: ein `dialog` mit schwarzem
   Rahmen, kein runder Kasten, kein Schatten als Tiefe. Nur breiter, weil ein
   Formular hineingeht - und auf dem Telefon nimmt sie den Schirm, weil dort
   alles andere Gedraengel waere.

   **Scrollen darf sie**, und zwar nur sie: `max-height` und `overflow` liegen
   an der Schicht, nicht am Formular - sonst scrollt der Ort dahinter mit, und
   man verliert die Stelle, an der man war. */
/* Rahmen, Grund, Hoechsthoehe und das X kommen von `.schicht` - hier steht
   nur, was die Bilderschicht davon unterscheidet. */
/* Eine Zwischenueberschrift **im Inhalt** („Noch drei Zeilen"), nicht der Name
   in der Kopfzeile: Der ist seit dem 05.09.2026 ebenfalls ein `h2`, und `.up h2`
   traf ihn mit - Spezifitaet schlaegt Absicht. Dieselbe Korrektur wie bei
   `.hilfeschicht h2` weiter oben. */
.up .schicht-inhalt h2 { margin: 0 0 .2rem; }
.up-ort { margin: 0 0 1.2rem; color: var(--soft); font-size: .95rem; }
.up-form { display: grid; gap: 1.1rem; }

/* Die Nennung ist eine Zusage und keine Fussnote: Sie steht ueber dem Knopf,
   in Textgroesse, und nennt den Namen, der am Bild erscheint. */
.up-nennung { margin: 0; font-size: .9rem; font-weight: 700; }
.up-nennung:empty { display: none; }
.up-fuss { display: flex; flex-wrap: wrap; gap: .6rem; margin: 0; }

/* **Die Vorschau.** Sie beantwortet die Frage, die das Formular vorher offen
   liess: Ist das das richtige Bild? Ein Dateiname beantwortet sie nicht. */
.up-schau { margin: .6rem 0 0; }
.up-schau img {
  display: block; width: 100%; max-width: 15rem; height: auto;
  border: 1px solid var(--line);
}

/**
 * **Die Kamera nur, wo es eine gibt.**
 *
 * `capture="environment"` heisst auf dem Telefon „hintere Kamera, jetzt" und
 * auf dem Schirm „such dir eine Webcam" - und das waere ein Knopf, der etwas
 * anderes tut als er sagt. Die Abfrage `hover: none` mit `pointer: coarse`
 * trifft Finger und keine Maus; sie ist dieselbe, mit der die Ablage ihr „oder
 * hierher ziehen" weglaesst.
 */
.up-kamera { display: none; margin: .6rem 0 0; }
@media (hover: none) and (pointer: coarse) {
  .up-kamera { display: block; }
}
.up-kamera label { display: inline-block; cursor: pointer; }
.up-kamera:has(input:focus-visible) label { outline: 2px solid var(--strong); outline-offset: 2px; }

/**
 * **Der Weg zum Bild ist ein Satz, kein Knopf** (04.09.2026).
 *
 * Er steht unter der Galerie und gilt fuer die wenigen, die hier beitragen
 * duerfen - ein grosser Knopf haette wie ein Aufruf an alle ausgesehen. Der
 * Verweis darin ist ein `button` (es oeffnet sich etwas, es wird nichts
 * aufgerufen) und sieht aus wie ein Verweis: `.wie-link`.
 */
/* **Zentriert** (04.09.2026): Der Satz steht zwischen Galerie und Text, quer
   ueber die Spalte - links angeschlagen sah er aus wie der Anfang eines
   Absatzes, der dann nicht kommt. In der Mitte ist er, was er ist: ein
   Angebot zwischen zwei Abschnitten. */
/**
 * **Abstand nach oben, weniger als nach unten** (04.09.2026, vom Auftraggeber
 * gesetzt).
 *
 * Der Satz stand mit `margin-top: 0` direkt unter der Galerie und klebte am
 * letzten Bild. Zwei Fassungen spaeter steht er bei 1 rem oben und 1,6 rem
 * unten: genug Luft, um nicht zum Bild zu gehoeren, und naeher am Bild als am
 * Text darunter - er bezieht sich ja auf das Bild.
 */
.up-weg {
  margin: 1rem 0 1.6rem; color: var(--soft); font-size: .95rem; text-align: center;
}
/**
 * **Ein Knopf, der wie ein Verweis aussieht** - und nicht fett (04.09.2026).
 *
 * Das Fett kam von seinem ersten Ort: „Bild beitragen" steht auf der
 * Eintragsseite allein in einem grauen Satz und braucht dort Gewicht. In der
 * Bestandstabelle steht er neben „Bearbeiten", und das ist ein gewoehnlicher
 * Verweis - zwei Verweise in einer Zelle, von denen einer fett ist, sehen aus
 * wie eine Rangfolge, die es nicht gibt.
 *
 * Fett wird er deshalb nur noch dort, wo er allein steht (`.up-weg .wie-link`).
 */
.wie-link {
  border: 0; padding: 0; background: none; font: inherit; cursor: pointer;
  color: var(--strong);
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .16em;
}
/* **Auch dieser nicht fett** (04.09.2026). Er stand allein in seinem Satz und
   bekam dafuer Gewicht - aber der Satz ist leise („Du hast ein Bild von
   hier?"), und ein fettes Wort darin ruft lauter als der Satz selbst. Ein
   Verweis ist unterstrichen; das genuegt, um ihn zu finden. */
.wie-link:hover, .wie-link:focus-visible { text-decoration-thickness: 2px; }
.wie-link:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }

/**
 * **Eine Schicht mit einer Mail darin ist breiter** (05.09.2026) - eine Mail
 * ist auf 520 Pixel gesetzt, und darum herum will man noch etwas sehen: den
 * grauen Grund, auf dem sie im Postfach liegt.
 */
.up-breit { width: min(56rem, 94vw); }

/* **Der Kopf einer Mail** (06.09.2026) - Von, An, Betreff, und in der Vorschau
   der Einladung darunter der Eintrag. Beschriftung links, Angabe rechts, in
   einem Raster: So steht die Angabe an jeder Zeile an derselben Stelle, und
   der Kopf bleibt beim Lesen ein Block statt vier Saetze.

   **Eng gesetzt** - er ist die Anschrift des Briefes und nicht der Brief.
   Vorher stand hier eine Zeile mit 1,2 rem Abstand nach unten, dann kam die
   Luecke des Formularrasters obendrauf: zwei Abstaende fuer einen Uebergang. */
.mailkopf { margin: 0; font-size: .9rem; line-height: 1.4; }
.mailkopf dl {
  display: grid; grid-template-columns: auto minmax(0, 1fr);
  gap: .1rem .7rem; margin: 0;
}
.mailkopf dt { color: var(--soft); }
.mailkopf dd { margin: 0; color: var(--ink); overflow-wrap: anywhere; }
.mailkopf p { margin: 0; color: var(--soft); }

/* Die Einladung ist ein kurzes Formular mit einer Vorschau darin - ihre Teile
   stehen enger als im Bilderformular, damit Kopf, Zeile und Vorschau in den
   Blick passen, ohne zu rollen. */
#form-einladung { gap: .8rem; }
/**
 * **Der Rahmen geht bis an die Kanten der Schicht.** Er zieht sich um den
 * Innenabstand hinaus (`.schicht-inhalt` traegt 1,4 rem): Ein Vorschaufenster
 * mit Rand um den Rand sieht aus wie ein Bild in einem Bild.
 */
#mail-rahmen, #einladung-rahmen {
  display: block; width: calc(100% + 2.8rem); margin: .6rem -1.4rem 0;
  height: 60vh; border: 0; border-top: 1px solid var(--line); background: #fff;
}
/* Die Vorschau in der Einladungsschicht klappt auf - zu, bis jemand sie
   sehen will. */
.einladung-vorschau summary { cursor: pointer; font-weight: 600; font-size: .9rem; }
.einladung-vorschau[open] summary { margin-bottom: .4rem; }

.up-sperre h2 { margin: 0 0 .4rem; }
.up-sperre p { margin: 0 0 1rem; }

.zuschnitt {
  border: 1px solid var(--strong); border-radius: 0; padding: 1.4rem;
  max-width: min(26rem, 92vw); background: var(--paper); color: var(--ink);
}
.zuschnitt::backdrop { background: rgb(0 0 0 / .55); }
.zuschnitt h2 { margin: 0 0 .3rem; }
.zuschnitt-hilfe { margin: 0 0 1rem; color: var(--soft); font-size: .9rem; }
/* **Die Form des Fensters sagt, was herauskommt** - rund beim Profilbild und
   beim Zeichen, eckig beim Kopfbild. Das Seitenverhaeltnis setzt das Skript
   (`zuschnittZeichnen`), weil es zum Format gehoert und nicht zum Aussehen. */
.zuschnitt-flaeche {
  display: block; width: 320px; max-width: 100%;
  border-radius: var(--feld-radius); background: var(--shade);
  touch-action: none; cursor: grab; margin: 0 auto;
}
.zuschnitt-flaeche.ist-rund { border-radius: 50%; }
/* The logo is cut on the ground of the header - the circle in the dialog is
   the circle in the bar. */
.zuschnitt-flaeche.ist-logo { background: var(--nav); }
.zuschnitt-flaeche.ist-logo.ist-hell { background: var(--nav-ink); }
/* Day and end of an own event side by side. */
.haustermin-tage { display: grid; grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); gap: 0 1rem; }
.mein-kachel .tab-pillen { margin: 0 0 .35rem; }
/* The clicks by rubric over the ten names. */
.mappe-rubriken { margin: 0 0 .9rem; }
/* On the grey card the pill turns white, like every pill on grey. */
.mein-kachel .tab-pillen .terminzeile-ort { background: var(--card-ground); }
/* The choice of ground - only for the logo. */
.zuschnitt-grund { margin: 1rem 0 0; }
.zuschnitt-grund[hidden] { display: none; }
.zuschnitt-was { margin: 0 0 .2rem; font-weight: 600; }
.zuschnitt-flaeche:active { cursor: grabbing; }
.zuschnitt-flaeche:focus-visible { outline: 2px solid var(--strong); outline-offset: 3px; }
.zuschnitt-regler { margin: 1rem 0 0; }
.zuschnitt-regler input { width: 100%; }
.zuschnitt-fuss { display: flex; gap: .6rem; justify-content: flex-end; margin: 1.2rem 0 0; }

.feld-haken {
  display: grid; grid-template-columns: auto 1fr; gap: .6rem;
  align-items: start; font-size: .95rem; line-height: 1.45;
}
/**
 * **Neben einem Haken steht ein Satz, keine Beschriftung** (04.09.2026).
 *
 * Der Text erbte `font-weight: 700` von `.feld > span` - und damit standen die
 * Einwilligungen in der Bilderschicht, beim Bewerten und beim Vorschlagen als
 * fette Absaetze da. Genau die liest niemand: Eine Einwilligung, die wie eine
 * Ueberschrift gesetzt ist, sieht aus wie Kleingedrucktes in Grossbuchstaben.
 *
 * Textstaerke also - fett bleibt nur, was der Satz selbst hervorhebt
 * („**und in Werbemitteln für den Guide**").
 */
.feld-haken > span { font-weight: 400; }
.feld-haken input { margin-top: .2rem; }
/* Der Hinweis steht **unter** dem Satz, nicht dahinter (05.09.2026). Im Editor
   las sich das sonst als ein Wort: „Immer zugänglich, keine ZeitenFür Orte
   ohne Tür." - `small` ist von Haus aus inline, und hier liegt es im `span`
   neben dem Haken statt als eigene Zeile im `.feld`-Raster. */
.feld-haken .feld-hint { display: block; margin-top: .15rem; }

/* Der Anmeldecode: sechs Kaesten, einer je Ziffer.

   **Warum sechs Felder und nicht ein gesperrtes.** Ein einzelnes Feld mit
   gemalten Kaesten (Hintergrundverlauf plus `letter-spacing`) sieht identisch
   aus, haengt aber daran, dass die Ziffernbreite genau der Kastenbreite
   entspricht. Beim ersten Schriftwechsel stehen die Ziffern zwischen den
   Kaesten - und niemand sucht den Fehler im CSS eines Anmeldeformulars.

   **Feste Breite, kein `flex`.** Vorher teilten sich die sechs den Platz
   (`flex: 1 1 0` mit `max-width`). Das rechnet der Browser bei jeder Aenderung
   im Kasten neu, und eine Reihe, die sich neu berechnet, kann umbrechen. Bei
   sechs Zeichen gibt es nichts zu verteilen: `3.2rem` ist die Breite, fertig.
   Damit ist die Reihe in jedem Zustand gleich gross - getippt, leer, im Fokus.

   `flex-wrap: nowrap` ist der Riegel dahinter: Auf einem schmalen Telefon
   werden die Kaesten enger (`min-width: 0` am Behaelter reicht nicht), aber sie
   springen nie in eine zweite Zeile. Sechs Kaesten in zwei Zeilen sind kein
   Code mehr, sondern ein Raetsel. */
.code-boxen { display: flex; flex-wrap: nowrap; gap: .5rem; }
.code-boxen input {
  /* `width` **und** `flex-basis` auf dasselbe Mass: `width: 100%` erbt sonst
     von `.feld input` und traegt zur Rechnung bei. */
  flex: 0 1 3.2rem; width: 3.2rem; min-width: 0;
  font-size: 2rem; font-weight: 800; line-height: 1.2;
  text-align: center; font-variant-numeric: tabular-nums;
  padding: .5rem .2rem;
  /* Der Rahmen ist der Kasten - deshalb hier und nicht auf dem Behaelter.
     Er bleibt in **jedem** Zustand 1px: Eine dickere Linie im Fokus zieht den
     Inhalt nach innen, und der Kasten sieht dann kleiner aus. */
  border: 1px solid var(--line); background: transparent; color: inherit;
  /* Nimmt iOS den Innenschatten, den es Textfeldern von sich aus gibt. */
  appearance: none;
}
/**
 * **Auch hier faerbt der Fokus nur den Rahmen** - dieselbe Sprache wie bei den
 * uebrigen Feldern (04.09.2026).
 *
 * Dafuer musste eine Regel weichen, die ich Stunden vorher selbst geschrieben
 * hatte: `:valid` faerbte den Rahmen einer **gefuellten** Ziffer schwarz. Mit
 * dem Fokus in derselben Farbe waeren zwei Zustaende nicht mehr zu
 * unterscheiden - ein gefuellter Kasten haette beim Hineinklicken nichts getan.
 *
 * Der Verlust ist klein: Wie weit man ist, sagt die Ziffer selbst, und sie
 * steht in 2 rem und Schriftschnitt 800 da. Der Rahmen musste es nicht noch
 * einmal sagen. Zwei Zeichen fuer dieselbe Auskunft sind eins zu viel - und
 * eines davon stand dem Fokus im Weg.
 */
.code-boxen input:focus-visible {
  outline: none; border-color: var(--strong);
}
@media (forced-colors: active) {
  .code-boxen input:focus-visible { outline: 2px solid; outline-offset: 1px; }
}

/* Ein Riegel, der an der Stelle steht, an der er gilt - nicht als Sperre vor
   der ganzen Seite. Dieselbe Form wie die Tipp-Box und die Bestaetigung: Balken
   links, leichter Grund, eckige Ecken. */
.konto-hinweis {
  max-width: var(--text); margin: 0 0 1.4rem;
  border-left: 3px solid var(--strong);
  background: color-mix(in srgb, var(--strong) 5%, transparent);
  padding: .9rem 1.1rem;
}

/**
 * **Kein Strich mehr darueber.** Der Erklaersatz stand mit einer Haarlinie vom
 * Rest abgesetzt - das war die Grenze, die er brauchte, solange alles ohne
 * Flaeche auf der Seite lag. Seit der Inhalt auf einer Tafel steht, macht die
 * Tafel die Trennung, und ein Strich darin ist die zweite Antwort auf eine
 * Frage, die schon beantwortet ist. Der Abstand bleibt: Er sagt, dass der Satz
 * dazugehoert und nicht dasselbe ist.
 */
.konto-warum {
  margin: 1.6rem 0 0;
  font-size: .9rem; color: var(--soft); max-width: var(--text);
}

/* Die Trefferliste unter dem Suchfeld. Sie liegt **im Fluss** und nicht als
   Schwebe darueber: Auf einem Telefon deckt eine schwebende Liste das Feld ab,
   in das man gerade tippt. */
.konto-treffer { list-style: none; margin: .4rem 0 0; padding: 0; border: 1px solid var(--line); }
.konto-treffer li + li { border-top: 1px solid var(--line); }
.konto-treffer button {
  display: block; width: 100%; text-align: left; border: 0; background: none;
  padding: .6rem .8rem; font: inherit; cursor: pointer; color: inherit;
}
.konto-treffer button:hover, .konto-treffer button:focus-visible { background: var(--shade); }
.konto-treffer span { color: var(--soft); font-size: .9rem; }

.konto-liste { list-style: none; margin: .8rem 0 0; padding: 0; }
/* **Kein Strich zwischen den Zeilen.** Er trennte sie, solange die Liste nackt
   auf der Seite lag; auf der Tafel macht die Flaeche die Trennung nach aussen,
   und innen genuegt der Abstand. Derselbe Handgriff wie bei `.konto-warum`. */
.konto-zeile {
  display: flex; gap: 1rem; align-items: flex-start;
  padding: .9rem 0;
}
.konto-zeile img { object-fit: cover; background: var(--line); flex: none; }
.konto-zeile p { margin: .2rem 0 0; }

/* **What stands on the host's page** ("Mein Eintrag > Bilder") - the released
   images in the gallery's order, to look at, not to act on: no buttons, no
   handle. 3 : 2 like the editor's grid; the primary image carries a pill. */
.mein-bilder-raster {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: .75rem; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
}
.mein-bilder-raster li { position: relative; }
.mein-bilder-raster img {
  display: block; width: 100%; height: auto; aspect-ratio: 3 / 2; object-fit: cover;
  background: var(--line); border-radius: var(--thumb-radius);
}
.mein-bilder-raster .plan-pille { position: absolute; top: .4rem; left: .4rem; margin-left: 0; }

/* Der Zustand als Wort, nicht als Farbfleck: Ein gruener Punkt sagt nichts,
   wenn man ihn nicht sehen kann. Die Farbe kommt dazu, sie ersetzt nichts. */
/**
 * **Die Zustandsmarke** - ein gefuelltes Label, keine gefaerbte Zeile.
 *
 * Vorher stand hier nur eine Schriftfarbe, und sie griff nicht einmal: Die
 * Regeln waehlen `[data-status="..."]`, die Bewertungsliste schrieb aber
 * Klassen (`wartet`, `gut`, `fehler`). Der Zustand stand also voellig unfarbig
 * da - ein Fehler, den man nur sieht, wenn man weiss, dass dort Farbe sein
 * sollte. Ein Vokabular, ein Selektor: `data-status`.
 *
 * **Eine Pille** (07.09.2026, auf Entscheidung). Hier stand `border-radius: 0`
 * mit der Begruendung „eine Pille waere das erste runde Element auf der ganzen
 * Seite" - das stimmt nicht mehr: Suchschlitz, Profilbild, Telefonrahmen, das
 * Plus auf der Zeilenlinie und der Erklaerungskasten sind vor ihr da. Und die
 * Form sagt etwas: Eine Marke ist nichts, was man anklickt. Rund unterscheidet
 * sie von jedem eckigen Knopf und jedem eckigen Feld daneben - in der
 * Bestandstabelle, in der Bild- und in der Vorteilszeile steht sie genau
 * dazwischen.
 *
 * Sie ist damit die **sechste dokumentierte Ausnahme** von `border-radius: 0`
 * und gilt nur fuer dieses Bauteil. Die Innenabstaende wachsen mit: In einer
 * Pille sitzt das Wort sonst an der Rundung.
 *
 * **Und die Farbe ist eine Zugabe, nicht die Aussage.** Das Wort steht im
 * Label; wer die Farben nicht unterscheiden kann, liest "wartet auf Pruefung".
 */
.konto-status {
  display: inline-block;
  padding: .15rem .6rem;
  border-radius: 999px;
  font-size: .8rem;
  font-weight: 700;
  background: var(--shade);
  /* `--ink` und nicht `--soft`: Auf `--shade` kommt Grau 600 bei dieser
     Schriftgroesse auf 4,45 - knapp unter AA (4,5). Der Rueckfall greift nur
     bei einem unbekannten Wert, aber auch der muss lesbar sein. */
  color: var(--ink);
}
.konto-status[data-status="new"],
.konto-status[data-status="submitted"],
.konto-status[data-status="revision"] {
  background: var(--state-wait-bg);
  color: var(--state-wait-ink);
}
.konto-status[data-status="published"] {
  background: var(--state-live-bg);
  color: var(--state-live-ink);
}
/* **Die Zustaende eines Eintrags** (04.09.2026). Dieselben Kaesten wie bei den
   Bildern, zwei Schluessel mehr: `verified` ist ein Entwurf, `proposed` ein
   willkuerlicher Vorschlag. Beide sind **nicht oeffentlich** und tragen deshalb
   dieselbe Farbe wie „in Pruefung" - nicht die von „online", denn genau das
   sind sie nicht. `published` und `rejected` teilen ihre Farbe mit den
   Bildern, weil sie dasselbe bedeuten. */
.konto-status[data-status="verified"],
.konto-status[data-status="proposed"] {
  background: var(--state-wait-bg);
  color: var(--state-wait-ink);
}

/* **Die Zahlen sind die Filter** (04.09.2026). Vorher standen Kacheln mit
   Zahlen und darunter Knöpfe mit denselben Wörtern - zwei Bauteile für
   dieselbe Sache. Jetzt ist jede Kachel ein Knopf.

   Der Knopf füllt die Kachel ganz aus (`display: block`, volle Breite), damit
   die Trefferfläche die Kachel ist und nicht ein Wort darin - am Handy der
   ganze Unterschied. Rahmen und Grund kommen von der Kachel, der Knopf selbst
   ist unsichtbar: Ein Knopf, der wie ein Knopf aussieht, wäre in einer Reihe
   von sieben eine Wand aus Rahmen. */
.bk-zahlen-wahl li { padding: 0; }
.bk-zahlen-wahl button {
  display: block; width: 100%; text-align: left;
  border: 0; background: none; padding: 1.1rem 1.2rem;
  cursor: pointer; color: inherit; font: inherit;
}
.bk-zahlen-wahl button:hover { background: var(--shade); }
.bk-zahlen-wahl button:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
/* Die gewählte Kachel: Balken links statt Vollfläche - eine invertierte Kachel
   in einer Reihe von sieben schreit, und die Zahl darin verliert ihre Ruhe. */
.bk-zahlen-wahl button[aria-pressed="true"] {
  box-shadow: inset 3px 0 0 var(--strong);
  background: var(--shade);
}
.bk-zahlen-wahl button[aria-pressed="true"] .bk-zahl-wort { color: var(--strong); }


.konto-status[data-status="rejected"] {
  background: var(--state-stop-bg);
  color: var(--state-stop-ink);
  text-decoration: line-through;
}
.konto-notiz { font-size: .88rem; color: var(--soft); max-width: var(--text); }

/* --- Die Prueflliste ---------------------------------------------------- */
.pruef-zeile { align-items: flex-start; gap: 1.2rem; flex-wrap: wrap; }
.pruef-text { flex: 1 1 18rem; min-width: 0; }
.pruef-kopf { margin: 0; font-weight: 700; }
.pruef-von { display: block; font-weight: 400; font-size: .85rem; color: var(--soft); }
.pruef-alt { margin: .4rem 0 .2rem !important; color: var(--ink); }
.pruef-knoepfe { display: flex; flex-wrap: wrap; gap: .6rem; align-items: center; margin-top: .8rem; }
.pruef-grund {
  flex: 1 1 14rem; min-width: 0; padding: .55rem .7rem;
  border: 1px solid var(--line); background: var(--paper); color: var(--ink); font: inherit;
  font-size: .92rem;
}
/**
 * **Der Wortlaut in der Prueflliste - ein Feld, kein Absatz.**
 *
 * Er sah vorher aus wie Text (`.pruef-alt`) und ist jetzt bearbeitbar: Ein
 * Tippfehler wird hier geradegezogen, statt die Stimme dafuer abzulehnen. Die
 * Anfuehrungszeichen fallen damit weg - ein Eingabefeld braucht keine, und in
 * einem Feld waeren sie beim Bearbeiten im Weg.
 */
.pruef-fassung {
  display: block; width: 100%; margin: .4rem 0 .2rem;
  padding: .55rem .7rem; resize: vertical;
  border: 1px solid var(--line); background: var(--paper); color: var(--ink); font: inherit;
  font-size: .95rem; line-height: 1.5;
}

/* Eine Meldung, die etwas taugt: Fehler und Erfolg unterscheiden sich, aber
   nicht nur durch Farbe - die Worte sagen es ohnehin. */
.count.fehler { color: var(--strong); font-weight: 700; }
.count.gut { color: var(--strong); }

/* ===========================================================================
   DIE MELDELEISTE - jede Meldung, jede Seite
   ===========================================================================

   Sie liegt am **unteren** Rand und in der Mitte: Auf dem Telefon ist das die
   Ecke, in der der Daumen ohnehin steht, und auf dem Schirm ist es der Weg,
   den das Auge nach einem Klick auf „Speichern" von selbst geht. Oben waere
   sie unter der Huelle, und die klebt schon.

   Schwarz auf Weiss mit einem Rahmen, wie alles hier - **keine Kante rund**
   (Styleguide) und kein grüner Balken: Die Art steht im Wort, die Farbe
   traegt sie nicht. Der Fehler bekommt den einen Unterschied, den er braucht:
   einen fetten Strich links, damit er in einem Stapel sofort auffaellt.

   `z-index` liegt ueber der Huelle (20) und dem Quadrat in der Ecke (21), aber
   unter dem Leuchtkasten - ein Bild im Vollbild ist ein eigener Zustand. */
.snack-leiste {
  position: fixed; z-index: 40;
  left: 50%; transform: translateX(-50%);
  /* Die Einwilligungsschicht sagt, wie hoch sie ist, **wenn** sie dieser Leiste
     im Weg steht (`chrome.js consentSnackBottom` misst die zwei Rechtecke
     gegeneinander). Ein Token, keine zweite Leiste - und auf einem weiten
     Schirm, wo die Schicht links unten steht und die Leiste mittig, bleibt der
     Wert bei 1rem. */
  bottom: var(--snack-bottom, 1rem);
  width: min(28rem, calc(100vw - 2rem));
  display: flex; flex-direction: column; gap: .5rem;
  /* Ohne Meldung ist hier nichts - und nichts, was einen Klick abfaengt. */
  pointer-events: none;
}
.snack {
  pointer-events: auto;
  /* Drei Spalten: Wort, wahlweise der Rueckweg, das Kreuz. Fehlt der Rueckweg,
     faellt seine Spalte in sich zusammen - `auto` auf nichts ist null. */
  display: grid; grid-template-columns: 1fr auto auto; align-items: start; gap: .5rem;
  background: var(--paper); color: var(--ink);
  border: 1px solid var(--strong);
  /**
   * **Leicht gerundet - eine der dokumentierten Ausnahmen** (05.09.2026).
   *
   * Ecken sind Marke (`border-radius: 0`, Styleguide), und das gilt fuer alles,
   * was zur **Seite** gehoert. Die Meldeleiste gehoert ihr nicht: Sie liegt
   * darueber, kommt fuer vier Sekunden und geht wieder - dieselbe Klasse
   * Bauteil wie die Hilfe-Pille oder das Vorschaubild. 6 px reichen; mehr
   * waere ein Kaestchen aus einer anderen Oberflaeche.
   */
  border-radius: 6px;
  padding: .7rem .7rem .7rem .9rem;
  box-shadow: 0 2px 12px rgb(0 0 0 / 12%);
  animation: snack-auf .18s ease-out;
}
/* **Normal gesetzt, in jeder Lage.** „Gut" und „Fehler" standen fett; eine
   Meldung ist aber ein Satz und keine Ueberschrift, und in einer Leiste, die
   ohnehin am Rand aufpoppt, braucht sie kein zweites Mittel, um aufzufallen.
   Was die Sorte sagt, bleibt: die Farbe des Worts und der Strich links. */
.snack-wort { margin: 0; font-size: .95rem; line-height: 1.45; font-weight: 400; }
.snack-gut .snack-wort { color: var(--strong); }
.snack-fehler {
  border-left-width: 4px;
}
.snack-fehler .snack-wort { color: var(--strong); }
/**
 * **Der Rueckweg in der Meldung** (06.09.2026) - „Gelöscht. [Zurückholen]".
 *
 * Er sieht aus wie ein Verweis und nicht wie ein Knopf: Ein gefuellter Knopf
 * in einer Leiste, die von selbst verschwindet, waere der lauteste Punkt auf
 * dem Schirm fuer die Handlung, die man am seltensten braucht. Unterstrichen,
 * in der Schriftfarbe, mit Platz fuer den Daumen.
 */
.snack-tun {
  flex: none; border: 0; background: none; padding: .2rem .1rem; margin-left: .3rem;
  font: inherit; font-weight: 700; color: var(--strong); cursor: pointer;
  text-decoration: underline; text-underline-offset: .16em;
}
.snack-tun:hover { text-decoration-thickness: 2px; }
.snack-tun:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
.snack-zu {
  display: grid; place-items: center;
  width: 1.75rem; height: 1.75rem; padding: 0; margin: -.1rem -.1rem 0 0;
  border: 0; background: none; color: var(--soft); cursor: pointer;
}
.snack-zu:hover { color: var(--strong); }
.snack-zu:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
.snack-zu svg { width: 1rem; height: 1rem; }

@keyframes snack-auf {
  from { opacity: 0; transform: translateY(.5rem); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .snack { animation: none; }
}

/* ===========================================================================
   DAS BACKEND
   ===========================================================================
   Sidebar links, ein Bereich rechts - Form nach dem Vorbild des Clubs der
   Entdecker. Es ist eine **Arbeitsansicht**, kein Schaufenster: dichter
   gesetzt, weniger Luft, keine Bilderbuehne. Was hier zaehlt, ist die Zahl der
   Zeilen, die auf einen Blick passen. */

/**
 * **Das Backend steht auf grauem Grund, drinnen liegen weisse Flaechen.**
 *
 * Die Statistikkachel hat keinen Rahmen mehr - ihre Grenze ist der
 * Helligkeitsschritt zum Grund (siehe `--card-ground`). Auf `--paper` waere
 * das Weiss auf Weiss, und die Oberkante verschwaende: Der Schatten faellt nur
 * nach unten, nach oben gibt es keinen. Der Grund ist also nicht Geschmack,
 * sondern die Bedingung, unter der eine rahmenlose Kachel ueberhaupt eine
 * Kachel ist.
 *
 * **`--shade` rueckt dabei eine Stufe nach**, und zwar hier und nur hier: Es
 * ist im Haus die leise Fuellung (Zeile unter der Maus, Codeblock, leeres
 * Bildfeld, Platzhalter) und stand auf demselben Wert, den der Grund jetzt
 * einnimmt - zweiundvierzig Flaechen waeren damit unsichtbar geworden, ohne
 * dass eine davon einen Fehler geworfen haette. Es bleibt die **dunklere**
 * Stufe gegen die Flaeche, auf der es liegt; das ist seine Aufgabe, und die
 * aendert sich nicht.
 *
 * **Draussen aendert sich nichts.** Die Regel haengt an `body.backend`, also
 * an der einen Seite, die das Backend ist (`web/profil.html`).
 */
body.backend {
  background: var(--backend-ground);
  --shade: #eceff1;
}
:root[data-theme="dark"] body.backend { --shade: #232a30; }

.bk {
  /**
   * **Zwei Token, und das ist der Punkt.**
   *
   * `--bk-nav-breite` ist die Breite, die der Mensch zieht (der Griff schreibt
   * sie als Stilattribut an `.bk`); `--bk-nav-spalte` ist die, die gerade
   * gilt. Eingeklappt ueberschreibt eine Regel die **zweite** - stuende dort
   * nur eine, gewaenne das Stilattribut vom Ziehen, und die Leiste bliebe
   * breit.
   *
   * **13 rem ist die Untergrenze** des Griffs, nicht ein runder Wert:
   * „Öffnungszeiten" ist das laengste Wort in der Navigation und passt dort
   * mit dem Polster noch in eine Zeile. Wer weiter kuerzt, bekommt Umbrueche -
   * und eine Navigation, deren Zeilen zweizeilig werden, liest sich als Liste
   * von Absaetzen. Nach oben sind es 26 rem: Darueber ist es keine Spalte
   * mehr, sondern eine zweite Seite.
   */
  /* Der Abstand der Spalte zur Fensterkante - als Token, weil der Schalter im
     eingeklappten Zustand dagegen rechnet: Seine Flaeche soll von Kante zu
     Kante gehen, sein Zeichen aber auf der Flucht der Marke stehen. */
  --bk-nav-polster: 1.75rem;
  --bk-nav-breite: 20rem;
  --bk-nav-spalte: var(--bk-nav-breite);
  display: grid; gap: 0;
  max-width: 1400px; margin: 0 auto 4rem; padding: 0 1.25rem;
}

/* ---------------------------------------------------------------------------
   THE CONSENT LAYER - the question about measuring, at the bottom edge

   A `<dialog>`, opened with `show()` and not `showModal()`: before the click
   nothing reaches Google, so there is no urgency that would justify a backdrop
   locking the page. It is a `dialog` all the same - that is the element the
   eight layers of this house use, and a `<div class="banner">` would be a
   ninth pattern for something that already exists.

   **No shadow and no rounded corner.** The message bar has both because it
   floats and leaves after four seconds; this one sits on the window edge and
   is bounded by it. So it is not a new exception to `border-radius: 0` - it is
   the rule.

   `position: fixed`, because the acceptance run measures CLS and it stands at
   zero: a strip in the flow would push the page down.

   `z-index: 30` - above the chrome (20) and the square in the corner (21),
   below the message bar (40) and below the lightbox, where a picture in full
   screen is a state of its own. */
.consent {
  position: fixed; z-index: 30;
  left: 0; right: 0; bottom: 0; top: auto;
  margin: 0; padding: 1rem;
  /* **`width: auto` steht ausdruecklich da.** Ein `dialog` traegt vom Browser
     `width: fit-content`; mit `left: 0; right: 0` bliebe er so breit wie sein
     laengster Satz und nicht so breit wie das Fenster - bei einer kurzen
     Ueberschrift also schmaler, als er sein soll. `.schicht` umgeht dasselbe
     mit einer festen Breite; die geht hier nicht, weil diese Schicht die
     Fensterkante sucht. */
  width: auto; max-width: none; max-height: 70dvh;
  display: flex; flex-direction: column; gap: .75rem;
  background: var(--paper); color: var(--ink);
  border: 0; border-top: 1px solid var(--strong); border-radius: 0;
}
.consent:not([open]) { display: none; }
.consent-title {
  display: flex; align-items: center; gap: .6rem;
  margin: 0; font-size: 1.15rem; line-height: 1.3; color: var(--strong);
}
/* The biscuit stands centred to the heading, also when it runs to two lines;
   1.6 rem with stroke 1.5 draws about the weight of the bold title. */
.consent-keks { width: 1.6rem; height: 1.6rem; flex: none; }
.consent-title:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* Only the text scrolls; the buttons stay. At one purpose this is never
   needed - the rule stands for the day a second one is asked about. */
.consent-text { overflow-y: auto; display: flex; flex-direction: column; gap: .5rem; }
.consent-text p { margin: 0; font-size: .95rem; line-height: 1.45; }
.consent-more { color: var(--soft); }
.consent-more a { color: var(--strong); }
/* **Die Liste der Zwecke** - es gibt sie erst ab zwei gefragten (siehe
   `chrome.js consentLayer`). Ein echtes Ankreuzkaestchen, kein nachgebautes:
   Tastatur, Vorleseprogramm und der Waehler auf dem Telefon kommen vom
   Browser, und die Beschriftung ist das `<label>` darum. */
.consent-zwecke { list-style: none; margin: 0; padding: 0; display: flex;
  flex-direction: column; gap: .5rem; }
.consent-zweck {
  display: flex; gap: .6rem; align-items: start; cursor: pointer;
  border: 1px solid var(--line); padding: .6rem;
}
.consent-zweck:hover { border-color: var(--strong); }
/* **Der Regler ist das Ankreuzkaestchen selbst** (`appearance: none`) -
   Tastatur, Vorleseprogramm und die Beschriftung ueber das `<label>` kommen
   damit vom Browser, und was hier steht, ist nur die Zeichnung.

   **Rund: die dokumentierte Ausnahme 4** von `border-radius: 0`, neben dem
   Suchschlitz, den Portraits und dem Plus auf der Zeilenlinie. Der Grund ist
   derselbe - die runde Form ist die **Form des Bauteils** und kein runder
   Kasten: Ein Regler ist ein Punkt, der in einer Bahn laeuft.

   Der Punkt hat eine eigene Groesse (`--punkt`), und beide Enden lesen sie:
   links `1px`, rechts `100% - Punkt - 1px` - dieselbe Luft, gespiegelt. Aus
   der Bahnhoehe gerechnet lag die zweite Seite um die zwei Rahmen daneben. */
/* **`input` steht mit im Selektor, und das ist kein Zufall.** Die Hausregel
   fuer Kaestchen (`input[type=checkbox]`, oben) setzt 1,1 rem im Quadrat und
   hat mit ihrem Attributselektor die **hoehere** Spezifitaet als eine Klasse -
   ohne den Elementnamen war der Regler ein Quadrat von 17,6 px, und die Bahn
   gab es nicht. Nachgemessen, nicht geraten. */
input.consent-schalter {
  appearance: none; -webkit-appearance: none;
  flex: none; position: relative; margin: .1rem 0 0; padding: 0;
  width: 2.2rem; height: 1.2rem;
  border: 1px solid var(--strong); border-radius: 999px;
  background: none; cursor: pointer;
  --punkt: .9rem;
}
input.consent-schalter::after {
  content: ""; position: absolute;
  width: var(--punkt); height: var(--punkt);
  top: 50%; margin-top: calc(var(--punkt) / -2);
  left: 1px; border-radius: 50%;
  background: var(--strong);
  /* Die Bewegung ist die Rueckmeldung - und sie fehlt, wo sie stoert. */
  transition: left .15s ease;
}
/* Angeschaltet ist die Bahn gefuellt und der Punkt nimmt das Papier - der
   Punkt allein unterscheidet links von rechts zu leise. */
input.consent-schalter:checked { background: var(--strong); }
input.consent-schalter:checked::after {
  left: calc(100% - var(--punkt) - 1px);
  background: var(--paper);
}
input.consent-schalter:focus-visible { outline: 2px solid var(--strong); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  input.consent-schalter::after { transition: none; }
}
.consent-zweck-wort { display: block; font-weight: 700; color: var(--strong); font-size: .95rem; }
.consent-zweck-satz { display: block; font-size: .9rem; color: var(--soft); line-height: 1.4; }

/* Both buttons share the width, so neither can be the louder one. */
.consent-buttons { display: flex; gap: .75rem; }
/* **„Auswahl speichern" steht darunter und leiser.** Ablehnen muss so laut
   sein wie Annehmen; ein dritter gleich grosser Knopf machte aus zwei Enden
   drei Moeglichkeiten, von denen die mittlere am meisten Arbeit macht. */
.consent-save {
  align-self: center; border: 0; background: none; padding: .25rem;
  font: inherit; font-size: .9rem; color: var(--soft);
  text-decoration: underline; cursor: pointer;
}
.consent-save:hover { color: var(--strong); }
.consent-save:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
.consent-buttons .action { flex: 1; justify-content: center; text-align: center; }

/* Without a pointing device a button is a thumb target. */
@media (pointer: coarse) {
  .consent-buttons .action { min-height: 44px; }
}

/* ---------------------------------------------------------------------------
   THE NEWSLETTER INVITATION - a sheet from below, a card at the corner

   Opened with `show()` like the consent layer (`chrome.js inviteShow`): no
   backdrop, the page stays readable. **On the phone a sheet from the bottom
   edge, at most 60 % of the height** - the text above it stays visible, and a
   whole screen would be a wall for something nobody ordered. **On a screen a
   card at the bottom right**: the bottom centre belongs to the message bar
   and the consent layer - the invitation waits while another layer is open.

   `z-index: 30` like the consent layer - above the chrome, below the message
   bar (40), which moves up over it through `--snack-bottom`. */
.schicht.einladung {
  position: fixed; z-index: 30;
  left: 0; right: 0; bottom: 0; top: auto;
  margin: 0; width: auto; max-width: none; max-height: 60dvh;
  border: 0; border-top: 1px solid var(--strong);
}
.einladung .schicht-kopf-wort { font-size: 1.15rem; }
/* No line under the head row - the invitation is one short card, and a rule
   between its name and its first sentence cut it in two. */
.einladung .schicht-kopf { border-bottom: 0; }
/* The heading takes the focus so a keyboard and a screen reader land in the
   layer - it is not a control, so it shows no ring. */
.einladung .schicht-kopf-wort:focus { outline: none; }
.einladung .schicht-inhalt { padding: 1rem 1.25rem 1.25rem; display: flex; flex-direction: column; gap: .8rem; }
.einladung-satz { margin: 0; font-size: .95rem; line-height: 1.45; }
.einladung-vorteile { list-style: none; margin: 0; padding: 0; display: grid; gap: .4rem; font-size: .95rem; line-height: 1.4; }
.einladung-vorteile li { display: flex; gap: .5rem; align-items: flex-start; }
.einladung-vorteile .nav-icon { width: 1.05rem; height: 1.05rem; flex: none; margin-top: .15rem; }
.einladung .waldpost-recht { margin: 0; }
@media (min-width: 34rem) {
  .schicht.einladung {
    left: auto; right: 1.5rem; bottom: 1.5rem;
    width: min(25rem, calc(100vw - 3rem));
    max-height: min(36rem, calc(100dvh - 3rem));
    border: 1px solid var(--strong);
  }
}
/* It comes up from the edge once - the only motion, and none where the
   device asks for none. */
@keyframes einladung-auf { from { transform: translateY(1.5rem); opacity: 0; } }
.schicht.einladung[open] { animation: einladung-auf .25s ease-out; }
@media (prefers-reduced-motion: reduce) {
  .schicht.einladung[open] { animation: none; }
}
/* **The round back button on the phone moves out** while the sheet is open -
   it floats bottom centre below 25 rem, exactly where the sheet lies. The
   same movement as with the search open. */
@media (max-width: 25rem) {
  html:not([data-mappe])[data-einladung="auf"] a.backsquare {
    transform: translateY(calc(100% + 2rem));
  }
}

/* On a screen a card at the **bottom centre**: on the axis of the page, where
   the eye ends up, and still out of the way of what is being read. It stays
   non-modal - no backdrop, the page behind keeps working, because before the
   click nothing reaches Google. The message bar stands at the same place, so
   it moves up over the card (`--snack-bottom`, measured in
   `chrome.js consentSnackBottom`). */
@media (min-width: 34rem) {
  .consent {
    left: 50%; right: auto; top: auto; bottom: 1.5rem;
    transform: translateX(-50%);
    width: min(45rem, calc(100vw - 3rem));
    border: 1px solid var(--strong);
    padding: 1.25rem;
  }
}



/* ---------------------------------------------------------------------------
   DAS BACKEND AUF DEM TELEFON (05.09.2026)
   ---------------------------------------------------------------------------

   **Die Navigation stand ueber dem Inhalt** - neun Gruppen, 22 Punkte, 651
   Pixel, an denen man bei jedem Aufruf vorbeirollte. Auf einem Schirm ist eine
   Spalte links richtig; auf einem Telefon gibt es kein Links.

   Jetzt eine feste Zeile oben: **wo man ist** und **der Weg woandershin**. Das
   Menue selbst ist die vorhandene Navigation, nur als Flaeche darueber - kein
   zweites Bauteil, keine zweite Ordnung. Wer wenige Bereiche hat, bekommt sie
   direkt als wischbare Reihe: Ein Menue fuer vier Punkte ist ein Griff zu viel. */
/**
 * **Der Hamburger im Weinrot** (05.09.2026) - nur im Backend, nur auf dem
 * Telefon, an der Stelle, an der im Frontend die Lupe sitzt.
 *
 * Rot ist im Guide sonst der Rubrikton „Uebernachten" und die Farbe des
 * Zerstoerenden - hier ist es der **Markenton der Ecke**: Der Griff muss auf
 * einer Flaeche voller Tabellen und Zahlen sofort zu finden sein, und Schwarz
 * geht dort unter.
 */
.bk-leiste { display: none; }
/* The bar carries word mark and signet; the phone rule below shows the signet. */
.bk-leiste .signet-icon { display: none; }
@media (max-width: 55.99rem) {
  /**
   * **Die Leiste des Backends** (05.09.2026) - Bauart wie `.nav` in der Huelle:
   * ein Block in der Ecke, Zeichen und Knopf darin, nicht ueber die ganze
   * Breite. Nur die Farbe ist eine andere.
   */
  /* **Links, und darin das Menue zuerst** (05.09.2026): Der Daumen liegt auf
     dieser Seite des Geraets, und der haeufigste Griff im Backend ist der
     Wechsel des Bereichs - nicht der Weg zur Startseite. Das Zeichen steht
     daneben und sagt, wessen Backend das ist. */
  .bk-leiste {
    display: flex; align-items: center; gap: .7rem;
    position: fixed; top: 0; left: 0; z-index: 31;
    /* **Der Griff traegt die Farbe des Navigationsblocks** (`--nav`) - dieselbe
       wie die Leiste der Huelle draussen, und im Dunkelmodus dreht sie mit.
       Das Weinrot stand hier, solange sie neben der Leiste der Huelle lag und
       sich von ihr unterscheiden musste; die gibt es im Backend nicht mehr. */
    background: var(--nav);
    /* As high as the row (`--navheight`), with the 44-px menu button in its
       middle - the account block beside it has the same height, so the two
       read as one. */
    padding: calc((var(--navheight, 3.7rem) - 2.75rem) / 2) .8rem;
  }
  .bk-leiste .nav-logo { fill: var(--nav-ink); }
  .bk-leiste .nav-link { color: var(--nav-ink); }
  .bk-leiste .nav-link:hover, .bk-leiste .nav-link:focus-visible {
    color: var(--nav-ink);
    background: color-mix(in srgb, var(--nav-ink) 18%, transparent);
  }
  /* The same round hover ground as the bell - a circle under one sign. */
  .bk-leiste .bk-burger { border-radius: 50%; }
  /**
   * **Und der Inhalt faengt darunter an** (05.09.2026).
   *
   * Die Leiste liegt fest ueber der Seite (`fixed`) und nimmt deshalb keinen
   * Platz ein - die erste Ueberschrift stand dahinter. Das Polster ist die
   * Hoehe der Leiste plus eine Zeile Luft, damit der Titel nicht an ihr klebt.
   */
  .bk { padding-top: calc(var(--navheight, 3.7rem) + 1.4rem); }
}

/* ---------------------------------------------------------------------------
   DAS BACKEND AUF DEM TELEFON (05.09.2026)
   ---------------------------------------------------------------------------

   **Die Navigation stand ueber dem Inhalt** - neun Gruppen, 22 Punkte, 651
   Pixel, an denen man bei jedem Aufruf vorbeirollte. Auf einem Schirm ist eine
   Spalte links richtig; auf einem Telefon gibt es kein Links.

   Jetzt eine feste Zeile oben: **wo man ist** und **der Weg woandershin**. Das
   Menue selbst ist die vorhandene Navigation, nur als Flaeche darueber - kein
   zweites Bauteil, keine zweite Ordnung. Wer wenige Bereiche hat, bekommt sie
   direkt als wischbare Reihe: Ein Menue fuer vier Punkte ist ein Griff zu viel. */
/**
 * **Der Hamburger im Weinrot** (05.09.2026) - nur im Backend, nur auf dem
 * Telefon, an der Stelle, an der im Frontend die Lupe sitzt.
 *
 * Rot ist im Guide sonst der Rubrikton „Uebernachten" und die Farbe des
 * Zerstoerenden - hier ist es der **Markenton der Ecke**: Der Griff muss auf
 * einer Flaeche voller Tabellen und Zahlen sofort zu finden sein, und Schwarz
 * geht dort unter.
 */
/* Der Knopf in der Leiste ist derselbe wie „Menü" in der Huelle (`.nav-link`) -
   hier steht nur, was ihn unterscheidet: Er traegt sein Zeichen etwas groesser,
   weil er allein in seiner Ecke steht. */
/* **Only the sign, no word** - three lines, and open the cross. At least
   44 px to hit, because without the word the sign is the whole target. */
.bk-burger { min-width: 2.75rem; min-height: 2.75rem; justify-content: center; }
.bk-burger .nav-icon { width: 1.25rem; height: 1.25rem; }
/**
 * **Im Backend gibt es die Lupe nicht.**
 *
 * Sie oeffnet die Suche des **Guide** - Eintraege, Termine, Beitraege fuer
 * einen Gast. Wer hier arbeitet, sucht im Bestand, und dafuer steht ueber
 * jeder Liste ihr eigenes Feld. Ein Griff, der an dieser Stelle etwas anderes
 * tut als ueberall sonst, ist schlimmer als keiner.
 *
 * Damit ist die obere linke Ecke frei, und die Navigation beginnt dort, wo der
 * Inhalt daneben beginnt (siehe `.bk-nav`, Polster oben).
 */
body:has(.bk) .suchknopf { display: none; }

/**
 * **Und die Leiste der Huelle gibt es hier auch nicht.**
 *
 * Sie traegt die Wege eines **Gastes** - Rubriken, Orte, Themen, das Magazin -
 * und die Marke. Beides steht im Backend woanders: die Bereiche in der Spalte
 * links, die Marke oben in ihr. Zwei Navigationen an zwei Ecken sind zwei
 * Ordnungen fuer einen Bildschirm, und die obere waere die falsche.
 *
 * **Damit faellt auch ihr Platz weg** - sie klebte oben und nahm 59 px im
 * Fluss. Die oberste Zeile bleibt trotzdem so hoch: Sie ist das Mass der Marke
 * oben in der Spalte (`--navheight` an `.bk-nav-kopf`) und der Leiste oben
 * rechts; der Inhalt beginnt darunter (`.bk-inhalt`, Polster oben).
 */
body:has(.bk) .chrome-nav { display: none; }

/**
 * **The backend keeps the room of the scroll bar, always.** With a classic
 * scroll bar (a mouse on a Mac, every Windows machine) a long area - the
 * folder with its preview - brings a bar of 15 px and a short one - the
 * subscription - takes it away; the window got 15 px wider, and everything
 * hung on its right edge or its middle moved. `stable` holds the gutter
 * whether the page scrolls or not; with overlay bars it costs nothing.
 */
html:has(.bk) { scrollbar-gutter: stable; }

@media (max-width: 55.99rem) {
  .bk-nav {
    position: fixed; inset: 0; z-index: 30;
    background: var(--paper); overflow-y: auto; overscroll-behavior: contain;
    /* Oben so viel Luft, wie das rote Quadrat hoch ist - es liegt darueber. */
    padding: calc(var(--navheight, 3.7rem) + 1rem) 1.25rem 2rem;
    display: none;
  }
  /* Zwei Klassen, weil die Grundregel von `.bk-nav` weiter unten steht und
     sonst mit ihrem eigenen Polster gewinnt. Oben so viel Luft, wie das rote
     Quadrat hoch ist - es liegt darueber. */
  .bk[data-nav-offen] .bk-nav {
    display: block;
    padding-top: calc(var(--navheight, 3.7rem) + 1rem);
    /* Eingerueckt wie der Inhalt der Seite - die Leiste haengt jetzt rechts,
       eine Achse unter ihr gaebe es nicht. */
    padding-left: 1.25rem;
  }
  /* **Auf- und zuklappen wie auf dem Schirm** (05.09.2026): Eine Gruppe ist
     offen, der Chevron sagt welche. Hier standen kurz alle offen - das war
     eine zweite Bedienung fuer dieselbe Navigation, und wer sie auf dem
     Telefon lernt, findet sie auf dem Schirm nicht wieder. */
}
@media (min-width: 56rem) {
  /* Die Spalte ist so breit, wie das laengste Wort sie braucht - und nicht
     breiter. Eine Navigation, die ein Drittel des Schirms nimmt, ist ein Menue
     mit Aussicht auf Arbeit. */
  /**
   * **Enger, in zwei Schritten** (04.09.2026): erst 2,5 auf 1,5 rem, dann auf
   * **1 rem** - und die Spalte von 15 auf **13 rem**.
   *
   * Die alten Masse stammen aus der Zeit, als rechts Formulare in Lesebreite
   * standen; dort ist Luft richtig. Rechts steht jetzt eine **Tabelle mit
   * sieben Spalten**, und die braucht jeden Zentimeter: Was die Luft gewinnt,
   * verliert der Titel, der sonst zehn Zeichen frueher abbricht. Zusammen sind
   * das 3,5 rem mehr fuer den Inhalt - rund sieben Zeichen.
   *
   * **13 rem ist die Untergrenze**, nicht ein runder Wert: „Öffnungszeiten" ist
   * das laengste Wort in der Navigation und passt bei 13 rem noch in eine
   * Zeile. Wer weiter kuerzt, bekommt Umbrueche in der Spalte - und eine
   * Navigation, deren Zeilen zweizeilig werden, liest sich als Liste von
   * Absaetzen.
   */
  /**
   * **Die Spalte steht an der Fensterkante, nicht im Rahmen.**
   *
   * Sie war die erste Spur eines 1400er Rahmens, der mittig stand - die
   * Navigation ruecke damit mit jedem breiteren Schirm weiter nach innen, und
   * der Inhalt bekam von der gewonnenen Breite nur die Haelfte. Jetzt sitzt
   * sie links am Fenster und der Inhalt nimmt den Rest: Die Navigation ist
   * **Teil des Fensters**, nicht des Blattes, an dem man arbeitet.
   *
   * Der Rahmen von 1400 px faellt damit weg. Er stuende dem Einklappen im Weg:
   * Auf einem 1920er Schirm bliebe der Inhalt offen wie geschlossen an
   * derselben Kante, und der Schalter taete sichtbar nichts. Der Preis steht
   * offen - die Buchseiten laufen ueber die ganze Breite, und das ist hier
   * schon die Entscheidung (siehe `.hb-text`).
   */
  .bk {
    grid-template-columns: var(--bk-nav-spalte) minmax(0, 1fr);
    gap: 0 1.5rem;
    max-width: none;
    margin-left: 0; margin-right: 0;
    padding-left: 0; padding-right: 1.25rem;
  }

  /**
   * **Eingeklappt bleibt eine Leiste stehen, keine Luecke.**
   *
   * Eine Navigation, die ganz verschwindet, nimmt ihren eigenen Rueckweg mit:
   * Der Knopf, der sie zurueckholt, stuende dann irgendwo anders. Die Leiste
   * ist so breit wie der Knopf darin - genug, um ihn zu treffen, und schmal
   * genug, dass der Inhalt die 13 rem wirklich bekommt.
   */
  /**
   * **Eingeklappt bleibt die Navigation stehen - nur ohne Worte.**
   *
   * Das ist der Grund, warum jede Gruppe ein Zeichen hat: Eine Leiste, in der
   * gar nichts mehr steht, ist keine Navigation, sondern eine Luecke mit einem
   * Knopf. So bleiben zwoelf Zeichen, jedes mit seinem Namen im `title`, und
   * ein Klick klappt die Spalte auf und die Gruppe dazu.
   *
   * 3,5 rem: das Zeichen (1,3) plus beidseitig Luft, die man mit dem Zeiger
   * trifft. Die Zeilen darunter (`ul`) gehen weg - sie tragen nur Worte.
   */
  /**
   * **Die Leiste ist so breit wie ihr Zeichen plus zweimal derselbe Rand.**
   *
   * 3,25 rem: das Zeichen misst 1,3, es bleiben zweimal **0,975 rem** - links
   * und rechts gleich. Das ist der Unterschied zu einer Spalte mit Polster:
   * Dort steht das Zeichen an einer Flucht, hier steht es **in der Mitte**,
   * und eine Mitte gibt es nur, wenn beide Raender gleich sind. Breiter waere
   * sie eine schmale Spalte mit viel Luft, schmaler traefe der Daumen nichts.
   */
  .bk[data-nav-zu] { --bk-nav-spalte: 3.25rem; }
  .bk[data-nav-zu] .bk-nav { padding-left: 0; }
  .bk[data-nav-zu] .bk-klapp { justify-content: center; }
  /* Was Worte traegt, geht: die Zeilen, die Namen der Gruppen
     und die Zeile mit dem Stand. In einer Leiste von 3,25 rem waere jede davon
     abgeschnitten - und eine abgeschnittene Auskunft ist keine. */
  .bk[data-nav-zu] .bk-nav ul,
  .bk[data-nav-zu] .bk-klapp > span,
  .bk[data-nav-zu] .bk-version { display: none; }
  .bk[data-nav-zu] .bk-nav nav > div { margin-top: .9rem; }
  /**
   * **Eingeklappt steht dort die Tanne - und der Schalter liegt darunter.**
   *
   * Nebeneinander ist in einer Leiste von 3,5 rem kein Platz, untereinander
   * waeren es zwei Zeilen fuer eine Ecke. Also teilen sie sich **einen**
   * Platz: Die Marke steht, und wer mit dem Zeiger hingeht, bekommt an
   * derselben Stelle den Weg zurueck. Das ist dieselbe Regel wie beim Plus auf
   * der Zeilenlinie - was man selten braucht, erscheint, wo man es sucht.
   *
   * **Ohne Zeigegeraet gibt es kein Zeigen**, also uebernimmt `:focus-within`:
   * Wer mit der Tabulatortaste hineinkommt, sieht den Schalter, und er bleibt
   * erreichbar, weil `opacity: 0` den Fokus nicht nimmt.
   */
  /* Der Kopf nimmt die ganze Leiste - so faengt das Zeigen an der Kante an und
     nicht erst am Zeichen. Mittig wie alles darunter. */
  .bk[data-nav-zu] .bk-nav-kopf {
    position: relative; justify-content: center;
    padding-left: 0; padding-right: 0;
  }
  /**
   * **Eingeklappt bleibt die Tanne** - als **Ausschnitt** derselben Wortmarke
   * und nicht als zweite Datei: Sie ist deren erstes Zeichen (24 von 272
   * Einheiten), also genuegen eine Breite und das `overflow: hidden` von oben.
   * 1,8 rem hoch mal 24/32 ergibt die 1,35 rem Breite.
   */
  .bk[data-nav-zu] .bk-logo { flex: none; width: 1.35rem; }
  /* **Eingeklappt gibt es nichts, was auslaufen koennte** - der Kopf ist dann
     so breit wie die Tanne, und ein Verlauf von 5 rem legte einen weissen
     Schleier ueber sie. */
  .bk[data-nav-zu] .bk-nav-kopf::after { display: none; }
  .bk[data-nav-zu] .bk-logo svg { width: auto; height: 1.8rem; }
  /**
   * **Die Flaeche geht von Kante zu Kante, das Zeichen bleibt auf der Flucht.**
   *
   * Der Schalter liegt im Kopf der Spalte, und der beginnt hinter deren
   * Polster - seine Flaeche beim Zeigen hoerte links davor auf und liess einen
   * Streifen stehen. In einer Leiste von vier Zeichenbreiten ist das die
   * Haelfte: Man zeigt auf die Marke und trifft nichts.
   *
   * In der Leiste faellt das Polster der Spalte weg, also reicht der Kopf
   * ohnehin von Kante zu Kante und der Schalter fuellt ihn aus (`inset: 0`).
   * Mittig wie das Zeichen, an dessen Stelle er tritt.
   */
  /**
   * **Der Schalter legt sich ueber die Marke, sie weicht ihm nicht.**
   *
   * Er traegt dafuer den Grund der Spalte (`--card-ground`) und deckt die
   * Tanne zu - beim Zeigen und im Fokus. Vorher blendete die Marke aus und der
   * Schalter ein; zwei Bewegungen fuer einen Handgriff, und in der Mitte stand
   * einen Wimpernschlag lang **beides halb da**. Eine Flaeche, die sich
   * darueberlegt, ist die einfachere Aussage: Hier liegt jetzt etwas anderes.
   *
   * Beim Zeigen wird der Grund `--shade` - dieselbe leise Fuellung wie unter
   * jedem Zeichen des Hauses, an dem man steht.
   */
  .bk[data-nav-zu] .bk-nav-schalter {
    position: absolute; inset: 0; margin: 0; padding: 0;
    /* **Die Verschiebung der Grundregel muss hier weg.** Aufgeklappt sitzt der
       Schalter an der rechten Kante und wird mit `translateY(-50%)` auf die
       Mitte gezogen; eingeklappt fuellt er den ganzen Kopf, und dieselbe
       Verschiebung hob ihn um seine halbe Hoehe **ueber** die Marke. `inset`
       schlaegt die Kanten, eine Transformation schlaegt es nicht. */
    transform: none;
    display: grid; place-items: center;
    background: var(--card-ground);
    opacity: 0; transition: opacity .18s ease;
  }
  .bk[data-nav-zu] .bk-nav-schalter:hover { background: var(--shade); }
  .bk[data-nav-zu] .bk-nav-kopf:hover .bk-nav-schalter,
  .bk[data-nav-zu] .bk-nav-kopf:focus-within .bk-nav-schalter { opacity: 1; }
  @media (prefers-reduced-motion: reduce) {
    .bk[data-nav-zu] .bk-nav-schalter { transition: none; }
  }
  .bk[data-nav-zu] .bk-nav-schalter { margin-left: auto; margin-right: auto; }

  /**
   * **Die Kante ist der Griff.**
   *
   * Ein Streifen von sieben Pixeln ueber der Trennlinie - breit genug, um ihn
   * mit der Maus zu treffen, schmal genug, dass er niemandem im Weg steht. Er
   * liegt `fixed` wie die Flaeche, die er begrenzt, und traegt selbst keine
   * Farbe: Zu sehen ist die Linie darunter, die beim Zeigen und im Fokus
   * dunkel wird. Ein eigener sichtbarer Balken waere ein zweiter Strich an
   * derselben Kante.
   *
   * Eingeklappt gibt es ihn nicht: Die Leiste ist so breit wie ihr Zeichen,
   * das ist keine Frage, die man ziehen koennte.
   */
  .bk-griff {
    display: block; position: fixed; top: 0; bottom: 0;
    left: calc(var(--bk-nav-spalte) - 3px);
    width: 7px; z-index: 22; cursor: col-resize;
    background: none; border: 0; padding: 0; touch-action: none;
  }
  .bk-griff::after {
    content: ""; position: absolute; top: 0; bottom: 0; left: 3px; width: 1px;
    background: transparent;
  }
  .bk-griff:hover::after,
  .bk-griff:focus-visible::after { background: var(--strong); }
  .bk-griff:focus-visible { outline: none; }
  .bk[data-nav-zu] .bk-griff { display: none; }
  /* Waehrend des Ziehens faengt nichts anderes den Zeiger - und es wird nichts
     markiert, was unter ihm liegt. */
  body.bk-zieht { user-select: none; cursor: col-resize; }

  /**
   * **Die Spalte ist eine durchgezogene helle Flaeche.**
   *
   * Sie steht auf demselben Papier wie eine Tafel - im Backend gibt es eine
   * Sorte Flaeche - und laeuft ueber die ganze Hoehe der Arbeit daneben. Die
   * Flaeche haengt deshalb am **Raster** und nicht an `.bk-nav`: Die Spalte ist
   * nur so hoch wie ihre Zeilen, weil sie klebt; die Flaeche soll so hoch sein
   * wie das, wovon sie den Rand bildet.
   *
   * **Ohne sie fehlte die Grenze genau dort, wo man sie braucht.** Rechts steht
   * meist eine weisse Tafel - aber Dashboard, Ueberblick und Mediadaten zeigen
   * Kacheln, und dort laegen Navigation und Inhalt auf demselben Grau. Eine
   * Grenze, die je nach Bereich da ist oder nicht, ist keine.
   *
   * Ein Strich an ihrer Kante, kein Schatten: Sie liegt nicht **auf** der
   * Seite, sie ist ihr Rand - und ein Schatten haette eine Richtung behauptet,
   * die eine Flaeche ohne Anfang und Ende nicht hat.
   *
   * **`fixed` und nicht `absolute`:** Am Raster festgemacht endete sie mit ihm
   * - oben blieb ein Streifen Grau, unten die 4 rem Abstand unter dem letzten
   * Inhalt, und beim Rollen lief sie mit. Der Rand eines Fensters hat aber
   * weder Anfang noch Ende: Er steht, und der Inhalt bewegt sich daran vorbei.
   * Ein Rechteck von Fensterkante zu Fensterkante braucht deshalb das Fenster
   * als Bezug und nicht den Kasten, in dem es zufaellig steht.
   */
  .bk { position: relative; }
  .bk::before {
    content: ""; position: fixed; top: 0; bottom: 0; left: 0;
    width: var(--bk-nav-spalte);
    background: var(--card-ground);
    border-right: 1px solid var(--line);
  }
  /* Zu heisst: der Pfeil im Zeichen dreht sich um - **nicht** das Zeichen.
     Gespiegelt wanderte der Strich des Kastens nach rechts, und das waere die
     Ansage einer rechten Spalte, die es hier nicht gibt. */
  .bk[data-nav-zu] .bk-nav-pfeil-zu { display: none; }
  .bk[data-nav-zu] .bk-nav-pfeil-auf { display: inline; }
}

/**
 * **Der Schalter der Spalte** - ein Chevron, sonst nichts.
 *
 * Er steht **oben in der Spalte und rechts**, also an der Kante, an der die
 * Spalte aufhoert: Dort zeigt der Pfeil auf das, was passiert, und nicht
 * irgendwohin. Ein Wort daneben braeuchte er nur einmal - beim ersten Mal -
 * und stuende danach in jeder Sitzung als Zeile ueber der Navigation; den
 * Namen traegt er deshalb als `aria-label` und `title`.
 *
 * Auf dem Telefon gibt es ihn nicht: Dort ist die Navigation eine Flaeche
 * ueber der Seite, und die schliesst der rote Griff.
 */
/**
 * **Der Kopf der Spalte: Marke links, Schalter rechts.**
 *
 * Die Marke fuehrt aus dem Backend heraus - dorthin, wohin sie auf jeder
 * anderen Seite fuehrt. Eingeklappt stehen beide untereinander in der Mitte
 * der Leiste.
 */
/**
 * **Der Kopf ist der Rahmen, in dem die Marke verschwinden darf.**
 *
 * `overflow: hidden` und `position: relative`: Die Marke behaelt beim
 * Schmalziehen ihre Groesse und laeuft unter den Schalter - der steht dafuer
 * absolut an der rechten Kante und traegt den Grund der Spalte. Sie
 * **schrumpft nicht mehr mit**: Eine Marke, die je nach Spaltenbreite eine
 * andere Groesse hat, ist an jedem Arbeitsplatz eine andere Marke; abgedeckt
 * ist sie dieselbe, nur weniger davon zu sehen.
 */
.bk-nav-kopf {
  position: relative; overflow: hidden;
  display: flex; align-items: center; justify-content: space-between;
  gap: .5rem; margin-bottom: 1.4rem;
}
/**
 * **Die Marke laeuft aus, sie bricht nicht ab.**
 *
 * Rechts im Kopf liegt ein Verlauf von durchsichtig nach Papier - die Flaeche,
 * unter der die Wortmarke verschwindet, wenn die Spalte schmal gezogen wird.
 * Eine harte Kante saehe aus wie ein Schnitt mitten im Wort („Black Forest
 * Pat|"); der Verlauf sagt **es geht weiter**, und dasselbe Papier traegt den
 * Schalter, der darin steht.
 *
 * `pointer-events: none`, damit er nichts abfaengt: Er ist eine Farbe, kein
 * Bauteil. Der Schalter liegt mit `z-index` darueber.
 */
.bk-nav-kopf::after {
  content: ""; position: absolute; right: 0; top: 0; bottom: 0; width: 5rem;
  background: linear-gradient(to right, transparent, var(--card-ground) 55%);
  pointer-events: none;
}
/**
 * **Der Kopf ist so hoch wie die Leiste der Huelle** - dann steht die Marke in
 * derselben Zeile wie die Marke rechts, und was darunter kommt, beginnt auf
 * der Hoehe, auf der auch der Inhalt beginnt.
 *
 * **Das Polster darunter ist dasselbe wie am Inhalt** (`.bk-inhalt`, 1 rem):
 * Die erste Gruppe steht damit auf der Flucht der Ueberschrift daneben - eine
 * Rechnung aus zwei vorhandenen Massen, kein abgemessener Wert, der bei der
 * naechsten Schriftgroesse danebenliegt.
 */
@media (min-width: 56rem) {
  /* Rechts ein Abstand zur Kante: Der Schalter sitzt sonst auf der Linie, die
     die Spalte begrenzt - und genau dort liegt der Griff, mit dem man sie
     zieht. Zwei Bedienungen an einem Pixel waeren eine zu viel. */
  .bk-nav-kopf { height: var(--navheight, 3.7rem); margin-bottom: 0; padding-right: 1rem; }
  .bk-nav nav { padding-top: 1rem; }
}
/**
 * **Auf dem Telefon steht die Marke in der Leiste, nicht in der Flaeche
 * darunter.**
 *
 * Am Schirm ist die Spalte immer da, und die Marke steht oben in ihr. Auf dem
 * Telefon ist die Spalte eine **Flaeche, die man aufmacht** - immer zu sehen
 * ist die Leiste mit dem Griff. Die Marke gehoert also dorthin, und der Kopf
 * der Spalte faellt weg: Er traegt dort nur noch sie (der Schalter zum
 * Einklappen erscheint erst ab 56 rem), und zwei Marken uebereinander sind
 * eine zu viel.
 *
 * **Die Absage steht hinter der Grundregel**, nicht im Layoutblock weiter
 * oben: Beide haben dieselbe Spezifitaet, und `display: flex` von hier schluege
 * ein `display: none` von weiter vorn. Derselbe Fehler wie beim Ziehgriff und
 * beim Polster der Spalte - dreimal dieselbe Falle, deshalb steht sie jetzt
 * dreimal als Regel daneben.
 */
@media (max-width: 55.99rem) { .bk-nav-kopf { display: none; } }
/**
 * **In der Spalte steht nur das Signet** - die Tanne, nicht die Wortmarke.
 *
 * Und zwar als **Ausschnitt** derselben Wortmarke, nicht als zweite Datei: Sie
 * ist deren erstes Zeichen (24 von 272 Einheiten breit), also genuegen eine
 * Breite und `overflow: hidden`. Eine eigene Signetdatei waere eine zweite
 * Quelle fuer dieselbe Marke - und die eine, die beim naechsten Feinschliff
 * vergessen wird.
 *
 * **Sie steht links und bleibt dort, auch eingeklappt.** Das ist der Grund,
 * warum die Leiste ihr Polster behaelt und die Zeichen darunter nicht mittig
 * stehen: Ein Zeichen, das beim Zuklappen um ein paar Pixel springt, liest
 * sich als Ruck - und die Marke ist der eine Punkt, an dem das Auge beim
 * Umschalten haengt.
 */
.bk-logo {
  display: block; overflow: hidden; line-height: 0;
  color: var(--strong);
  /**
   * **Aufgeklappt steht die ganze Wortmarke da - und sie geht mit.**
   *
   * `flex: 0 0 13.5rem` heisst: immer so breit.
   * Das SVG fuellt die Breite und rechnet seine Hoehe aus dem Seitenverhaeltnis
   * (272 : 32) - die Marke **schrumpft** also mit einer schmal gezogenen
   * Spalte, statt rechts abgeschnitten zu werden. „Black Forest Pat" waere
   * schlimmer als eine kleine Wortmarke.
   */
  flex: 0 0 13.5rem;
}
.bk-logo svg { width: 100%; height: auto; display: block; fill: currentColor; }

/* **Die Absage steht in einer eigenen Breitenabfrage**, nicht als blosse
   Grundregel: Der Block, der den Griff aufstellt, steht weiter oben im
   Stylesheet - eine unbedingte Regel hier schlaege ihn bei gleicher
   Spezifitaet einfach, und der Griff waere auf jedem Schirm weg. */
@media (max-width: 55.99rem) { .bk-griff { display: none; } }

.bk-nav-schalter {
  display: none;
  /* Er steht rechts im Kopf und **ueber** der Marke: Sie laeuft darunter
     weiter, und sein Grund deckt sie ab. Ohne den Grund staende das Zeichen auf
     der Wortmarke.

     **Mit Abstand zur Trennlinie** (.9 rem): Buendig an ihr las sich das
     Zeichen als Teil der Kante statt als Knopf, und seine Flaeche stiess an
     die Linie, ohne sie zu meinen. Das Polster links ist groesser (1,75 rem) -
     dort steht Text auf einer Flucht, hier ein Zeichen an einem Rand. */
  position: absolute; right: .9rem; top: 50%; transform: translateY(-50%);
  z-index: 1;
  background: var(--card-ground); border: 0; padding: .35rem; margin: 0;
  color: var(--soft); cursor: pointer; border-radius: 4px;
  line-height: 0;
}
.bk-nav-schalter svg { width: 1.3rem; height: 1.3rem; display: block; }
/* Von den zwei Pfeilen im Zeichen steht immer genau einer. */
.bk-nav-pfeil-auf { display: none; }
.bk-nav-schalter:hover { color: var(--strong); background: var(--shade); }
.bk-nav-schalter:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
@media (min-width: 56rem) {
  .bk-nav-schalter { display: block; }
}

/**
 * **Drei Masse, aus denen die Spalte ihre Flucht rechnet.**
 *
 * Die graue Leiste steht **genau unter dem Chevron** und der Text der Zeilen
 * **buendig mit der Ueberschrift**. Beides sind Rechnungen aus denselben drei
 * Zahlen - deshalb stehen sie hier und nicht dreimal als abgemessener Wert in
 * einer Regel. Wer den Chevron groesser macht, verschiebt die Leiste mit.
 */
.bk-nav {
  /* Etwas groesser als das Wort daneben (1,05 rem) - dieselbe Ueberlegung wie
     beim Pfeil der grossen Navigationszeile (`.nav-row .nav-icon`): Er ist die
     Handlung der Zeile, nicht ihre Fussnote. */
  --klapp-icon: 1.3rem;     /* Breite des Chevrons */
  --klapp-gap: .5rem;       /* Abstand vom Chevron zum Wort */
  --klapp-line: 2px;        /* Staerke der grauen Leiste */
  padding: 1rem 0 2rem;
}
@media (min-width: 56rem) {
  /**
   * Klebend: Bei hundert Zeilen in der Prueflliste soll der Weg zurueck nicht
   * hundert Zeilen weiter oben liegen.
   *
   * **Und ein Polster zur Fensterkante.** Die Spalte sitzt seit dem Umbau an
   * der Kante des Fensters, nicht mehr im Rahmen - ohne Polster klebte die
   * Schrift daran. Es steht **hier** und nicht im Layoutblock weiter oben: Die
   * Grundregel von `.bk-nav` steht dazwischen und raeumte mit ihrem
   * `padding: 1rem 0 2rem` jeden frueheren Wert wieder ab.
   *
   * Die Spalte ist um dasselbe Mass breiter geworden (13 auf 15 rem): Die
   * 13 rem waren die Breite, die „Öffnungszeiten" in einer Zeile braucht -
   * Polster von innen abgezogen haette das Wort umgebrochen.
   */
  .bk-nav {
    /**
     * **Die Spalte beginnt am Fensterrand.** Die Leiste der Huelle gibt es im
     * Backend nicht mehr, also gehoert die oberste Zeile ihr: `top: 0` fuer
     * das Kleben, und `z-index` eine Stufe ueber dem, was die Huelle sonst
     * noch fest stellt.
     */
    position: sticky; top: 0; align-self: start; z-index: 21;
    padding-left: var(--bk-nav-polster);
    /**
     * **Ist die Spalte hoeher als das Fenster, rollt sie selbst.**
     *
     * Ein klebendes Element haelt seine Oberkante oben fest - was darunter
     * nicht mehr ins Fenster passt, ist damit auf keinem Weg zu erreichen:
     * Die Seite rollt, die Spalte bleibt stehen. Bei zwoelf Gruppen und einem
     * kurzen Fenster lagen so der Regler, der Ausgang und die Versionszeile
     * unter der Kante. `100dvh`, weil auf einem Telefon die Adressleiste
     * mitrechnet - dort greift die Regel zwar nicht, aber die Zahl soll auch
     * nicht falsch dastehen.
     */
    max-height: 100dvh; overflow-y: auto; overscroll-behavior: contain;
    /* Die Marke sitzt ganz oben in der Ecke - seit die Lupe im Backend weg
       ist, gehoert sie ihr. Die Flucht mit dem Inhalt haelt nicht der
       Spaltenrand, sondern die **Navigation**: Sie beginnt auf der Hoehe der
       Ueberschrift daneben (siehe `.bk-nav-kopf`). */
    padding-top: 0;
  }
  /* Eingeklappt traegt die Leiste nur den Schalter - dort ist die Mitte die
     Flucht, kein Polster. */

}

/**
 * **Der Stand, auf dem die Anwendung laeuft** - ganz unten, leise, zweizeilig:
 * die Commitkennung in der Monospace, darunter der Zeitpunkt. **Grotesk sagt
 * was, Monospace sagt woher** - und eine Commitkennung ist das Woher in
 * Reinform.
 *
 * Sie steht ohne Ueberschrift da: Wer sie sucht, erkennt sie, und wer sie
 * nicht sucht, soll sie ueberlesen koennen. Leer ist sie ein Element ohne
 * Hoehe, also faellt sie weg, solange die Abfrage laeuft oder scheitert.
 */
/* The build stamp is a footnote to the navigation, not a part of it: room
   above and a hairline in between set it apart from the last menu group. */
.bk-version {
  margin: 2rem 0 0; padding-top: 1rem; border-top: 1px solid var(--line);
  display: grid; gap: .1rem;
  font-size: .78rem; color: var(--soft);
}
.bk-version:empty { display: none; }
.bk-version code { font-family: var(--mono); font-size: .95em; color: var(--ink); }
/**
 * **„Jetzt abmelden" mit dem Zeichen der Tuer** (04.09.2026).
 *
 * „Abmelden" allein steht wie eine Ueberschrift da - ein Wort in einer Spalte
 * voller Woerter. „Jetzt abmelden" ist eine Handlung, und das Zeichen davor
 * (dieselbe Tuer wie frueher im Quadrat) sagt es noch einmal ohne Text: Wer
 * die Spalte ueberfliegt, erkennt den Ausgang an der Form.
 */

/* Die Zeile „wer bin ich" ueber der Navigation ist weg (04.09.2026): Wer
   angemeldet ist, steht im Kontozeichen der Huelle und im ersten Satz des
   Profils - dreimal derselbe Name ist zweimal zu viel. */
/**
 * Die Gruppentitel der Navigation - **Überschriften, keine Etiketten**
 * (04.09.2026).
 *
 * Vorher waren sie klein, gesperrt, großgeschrieben und weich: die Form eines
 * Etiketts, wie man sie in Verwaltungsansichten findet. Bei drei Gruppen trug
 * das noch; bei vier Gruppen und zwölf Bereichen zerfiel die Spalte in gleich
 * aussehende Zeilen, in denen der Titel nicht mehr über der Liste stand,
 * sondern zwischen ihr.
 *
 * Jetzt Tintenschwarz, fett, in Textgroesse und ohne Grossschreibung - **ohne
 * Linie darunter** (04.09.2026): Die Zusammengehoerigkeit sagt jetzt die graue
 * Leiste an den Zeilen darunter, und zwei Formen fuer dieselbe Aussage sind
 * eine zu viel.
 *
 * **Gleicher Abstand für alle Blöcke.** `:first-of-type` fiel weg: Es meint
 * „erster im Elternelement", und seit die Redaktionsbereiche in einem eigenen
 * `<div>` stecken, traf es dort ein zweites Mal - der erste Titel der Redaktion
 * verlor seinen Abstand und klebte an der Liste über ihm. Statt einer Ausnahme
 * jetzt eine Regel: Abstand nach oben trägt jede Gruppe, und der erste bekommt
 * ihn über `.bk-nav nav > :first-child` weggenommen, egal in welcher Ebene.
 */
.bk-gruppe {
  margin: 1.6rem 0 .5rem;
  font-size: 1.05rem; font-weight: 700; color: var(--strong);
}

/* **Die Ueberschrift ist ein Knopf** (04.09.2026): Sie klappt die Gruppe auf
   und zu, immer nur eine offen. Der Knopf fuellt die Ueberschrift ganz aus -
   die Trefferflaeche ist die Zeile und nicht das Wort darin. Kein eigener
   Rahmen und keine eigene Farbe: Er soll aussehen wie die Ueberschrift, die er
   ist, nicht wie ein Knopf daneben. */
.bk-klapp {
  display: flex; align-items: center; gap: var(--klapp-gap);
  width: 100%; padding: 0; border: 0; background: none;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
}
/* **Beim Zeigen nur dunkler, ohne Unterstrich** (04.09.2026). Der Unterstrich
   ist die Form des Verweises im Fliesstext; in einer Spalte, die aus nichts
   als Verweisen besteht, sagt er nichts mehr und flackert nur.

   Vorher wurde die Ueberschrift beim Zeigen sogar **heller** (`--ink` statt
   `--strong`) - eine Zeile, die auf Beruehrung zurueckweicht, liest sich wie
   ein Fehler und nicht wie ein Angebot. */
.bk-klapp:hover { color: var(--strong); }
/* Der Chevron folgt seiner Zeile: Er ist grau, solange nichts mit ihm ist, und
   schwarz, sobald man ihn beruehrt oder er offen steht - dieselbe Achse wie bei
   den Zeilen darunter. */
.bk-klapp:hover .bk-zeichen { color: var(--strong); }
.bk-klapp:focus-visible { outline: 2px solid var(--strong); outline-offset: 3px; }
/* **Der Chevron steht vor der Ueberschrift**, nicht am Zeilenende - dieselbe
   Anordnung wie im Aufklapper der Huelle: Zeichen und Wort zusammen, und die
   Richtung liest man vor dem Text und nicht danach. `order` statt einer
   Aenderung im Markup, wie schon bei `.nav-back`.

   Er zeigt nach rechts und dreht beim Aufklappen nach unten - aufgeklappt zeigt
   er damit **genau auf die graue Leiste** darunter, also auf das, was er
   geoeffnet hat.

   **Grau, und schwarz wenn offen.** Zugeklappt ist er ein Angebot und soll die
   Ueberschrift nicht ueberstimmen; offen gehoert er zum Zustand und traegt
   dieselbe Farbe wie das Wort daneben. */
/**
 * **Das Zeichen der Gruppe steht vor ihrem Namen** - dort, wo bis dahin der
 * Chevron stand. Es sagt **welche** Gruppe, nicht ob sie offen ist; den Zustand
 * tragen die Liste darunter und `aria-expanded` am Knopf. Es dreht sich
 * deshalb nicht: Ein Zeichen, das seine Bedeutung wechselt, hat keine.
 *
 * **Grau, und schwarz wenn offen** - dieselbe Achse wie bei den Zeilen darunter.
 */
.bk-zeichen {
  flex: none; width: var(--klapp-icon); height: var(--klapp-icon);
  color: var(--soft);
}
.bk-klapp[aria-expanded="true"] .bk-zeichen { color: var(--strong); }
/**
 * **Gleicher Abstand zwischen allen Bloecken.**
 *
 * Jede Gruppe ist ein `<div>` - Titel und Liste zusammen. Der Abstand haengt
 * deshalb am Behaelter und nicht am Titel: Ein Titel weiss nicht, ob ueber ihm
 * eine Liste, ein anderer Titel oder der Rand steht, ein Behaelter schon.
 *
 * `:first-child` bleibt einfach, weil alle Bloecke dieselbe Ebene haben. Vorher
 * stand hier `.bk-gruppe:first-of-type` - das meint „erster im Elternelement",
 * und mit einem Behaelter fuer die Redaktion traf es dort ein zweites Mal: Der
 * erste Redaktionstitel verlor seinen Abstand und klebte an der Liste ueber ihm.
 *
 * **Ausgeblendete Bloecke zaehlen nicht mit**, weil `hidden` sie ganz entfernt -
 * wer keinen Betrieb hat, bekommt keine Luecke an dessen Stelle.
 */
/**
 * **Das Schloss an Gruppen und Punkten der Redaktion** (05.09.2026) - grau und
 * klein: Es ist eine Auskunft am Rand („das siehst nur du"), keine Warnung.
 * Beim aktiven Punkt zieht es mit, wie das Wort daneben.
 */
/**
 * **Klein, schwarz, auf der Grundlinie** (05.09.2026, in drei Schritten
 * gefunden: erst zu gross und grau, dann zu hoch).
 *
 * Schwarz, weil es keine Fussnote ist, sondern eine Eigenschaft der Zeile: „das
 * siehst nur du". Grau haette es zu einem Zusatz gemacht, den man ueberliest.
 */
.bk-schloss {
  flex: none; color: var(--strong); width: 11px; height: 11px;
  vertical-align: -.05em; margin-left: .2rem;
}

.bk-nav nav > div { margin-top: 1rem; }
.bk-nav nav > div:first-child { margin-top: 0; }
/* Der Titel traegt den Abstand nach unten, den Abstand nach oben der Block. */
.bk-gruppe { margin-top: 0; }
.bk-nav ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .1rem; }
/**
 * **Dieselbe Form wie die Abschnittnavigation** der Dokumentation
 * (`.hb-gruppe a`, 04.09.2026 auf Wunsch angeglichen).
 *
 * Vorher trug der aktuelle Bereich eine **gefuellte schwarze Flaeche**. Das war
 * fuer sich in Ordnung - aber in derselben Ansicht steht daneben die
 * Abschnittnavigation eines Buches, und die zeigte ihre offene Seite fett mit
 * einer Linie links. Zwei Formensprachen fuer dieselbe Aussage („hier stehe
 * ich") in einer Spalte; eine musste weichen, und es ist die laute.
 *
 * Die Leiste sitzt **immer** da und wechselt nur die Farbe - grau, schwarz am
 * aktuellen Punkt. So springt der Text beim Wechseln nicht um zwei Pixel.
 */
.bk-nav nav a {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  /* Leiste mittig unter den Chevron, Text auf die Flucht der Ueberschrift:
     Rand + Leiste + Polster ergeben zusammen `icon + gap`. */
  margin-left: calc(var(--klapp-icon) / 2 - var(--klapp-line) / 2);
  padding: .25rem 0 .25rem calc(var(--klapp-icon) / 2 + var(--klapp-gap) - var(--klapp-line) / 2);
  border-left: var(--klapp-line) solid var(--line);
  /* **Drei Zustaende, eine Farbachse** (04.09.2026): grau, was nur dasteht -
     schwarz, was man beruehrt oder wo man ist. Ohne Fettdruck und ohne
     Unterstrich traegt die Helligkeit die ganze Aussage, und dann muss der
     Abstand zwischen den Zustaenden sichtbar sein. */
  color: var(--soft); text-decoration: none; font-size: .95rem; line-height: 1.35;
}
.bk-nav nav a:hover { color: var(--strong); }
/**
 * **Eine Zeile bleibt eine Zeile - gekuerzt, nicht umgebrochen.**
 *
 * Die Spalte ist ziehbar, und ein Wort wie „Öffnungszeiten" passt schmal
 * gezogen nicht mehr in die Breite. Umgebrochen wird daraus ein Absatz von
 * zwei Zeilen, und eine Navigation aus Absaetzen liest sich nicht mehr als
 * Liste: Das Auge zaehlt Zeilen, nicht Punkte. Gekuerzt bleibt die Zeile eine
 * Zeile, und die Auslassungspunkte sagen, dass da noch etwas steht.
 *
 * **`min-width: 0` an beiden Stellen ist die halbe Miete**: Ein Flexkind
 * schrumpft von sich aus nur bis zu seiner Inhaltsbreite, und darueber hinaus
 * erst, wenn man es ihm ausdruecklich erlaubt. Ohne das ueberliefe die Zeile
 * die Spalte, statt zu kuerzen - sichtbar erst beim Ziehen.
 *
 * **Den ganzen Namen behaelt der `title`** des Gruppenknopfes und die Adresse
 * der Zeile; vorgelesen wird ohnehin der volle Text.
 */
/* **Auch die Zeile darum darf schrumpfen.** `.bk-nav ul` ist ein Raster, und
   ein Rasterkind steht von sich aus nie schmaler als sein Inhalt - der Verweis
   lief damit ueber die Spalte hinaus, statt zu kuerzen. */
.bk-nav ul li { min-width: 0; }
.bk-nav nav a { min-width: 0; }
.bk-nav nav a > span,
.bk-klapp > span {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* **Nicht fett** (04.09.2026): Fett gehoert der Ueberschrift, und zwar ihr
   allein - sie ordnet, die Zeile darunter ist eine von vielen. Dass hier
   jemand steht, sagen die schwarze Leiste und die dunklere Schrift; Fettdruck
   dazu war das dritte Mal dieselbe Aussage. */
.bk-nav nav a[aria-current="page"] {
  color: var(--strong);
  border-left-color: var(--strong);
  text-decoration: none;
}
.bk-zahl {
  min-width: 1.4rem; padding: .05rem .35rem; text-align: center;
  background: var(--line); color: var(--ink); font-size: .78rem; font-weight: 700;
}
/* Der Zaehler am aktuellen Punkt bleibt kraeftig. Seit die Zeile nicht mehr
   fett ist, traegt er sogar mehr: Leiste und Zaehler sind dann die beiden
   Zeichen, an denen man sieht, wo man steht. */
/**
 * **Und beim Zeigen schlaegt er um** (auf Wunsch): dunkle Flaeche, helle
 * Ziffer.
 *
 * `--paper` und nicht `#fff`: Die Ziffer ist der **Gegenton** zur Flaeche, und
 * im Dunkelmodus ist der Grund dunkel und `--strong` weiss - ein getipptes
 * Weiss waere dort weiss auf weiss. Dieselbe Paarung wie am aktuellen Punkt,
 * deshalb steht sie im selben Selektor.
 *
 * Der aktuelle Punkt bleibt unterscheidbar: Ihn markiert zusaetzlich die
 * **Leiste links** (`border-left-color`), und die hat das Zeigen nicht.
 */
.bk-nav nav a[aria-current="page"] .bk-zahl,
.bk-nav nav a:hover .bk-zahl { background: var(--strong); color: var(--paper); }

/* Kein Zugriff: eine Lesespalte statt der Schale.

   **Nicht in der Sidebar-Form.** Wer hier landet, hat keinen Bereich zu
   wechseln - ein leeres Menue daneben waere die Andeutung eines Zugangs, den es
   nicht gibt. Deshalb zentriert wie eine Textseite und nicht wie ein
   Arbeitsplatz. */
.bk-zu { max-width: var(--text); margin: 3rem auto; padding: 0 1.25rem; }
.bk-zu-kopf { font-size: 1.3rem; color: var(--strong); margin: 0 0 .5rem; }
.bk-zu p { margin: 0 0 1rem; }
.bk-zu .form-foot { margin-top: 1.4rem; }

/**
 * **Eine Flucht und eine Breite fuer alle Bereiche** (04.09.2026).
 *
 * Die Inhalte sprangen: Jeder Bereich fing an einer anderen Stelle an und war
 * anders breit - die Bestandsliste schmal und mittig, das Handbuch weiter
 * links, die Pruefliste irgendwo dazwischen. Es sah nach einem Fehler in jedem
 * einzelnen Bereich aus und war einer in der Spalte, die sie alle traegt.
 *
 * `main` bekommt in der Huelle `margin: 0 auto` - richtig fuer eine Seite, die
 * mittig in einem 1100er Rahmen steht. Hier ist `main` aber ein **Grid-Element**,
 * und dort saugen automatische Raender den freien Platz auf: Das Element
 * verliert seine Streckung, nimmt seine **Inhaltsbreite** (fit-content) und
 * stellt sich in die Mitte der Spur. Damit haengt die Flucht am Inhalt - eine
 * lange Zeile schiebt den ganzen Bereich nach links, eine kurze nach rechts.
 *
 * Deshalb hier `margin: 0`: Die Spur gibt die Flucht, und jeder Bereich
 * beginnt an derselben Kante. Wo ein Text schmaler sein soll, sagt es der Text
 * (`.lead`, `.hb-text` halten `--text`) - nicht die Spalte.
 *
 * **Und ab 56 rem ein Deckel von 1640 px, mittig in dem, was uebrig bleibt.**
 *
 * Der Inhalt nimmt, was da ist, aber nicht mehr als 1640 - darueber wird aus
 * einer Tabellenzeile eine Strecke, deren Anfang und Ende man nicht zusammen
 * sieht. Und **weil** er gedeckelt ist, kann er mittig stehen: Klappt die
 * Spalte ein, wandert er nicht nach links weg, sondern rueckt in die Mitte
 * des freien Raums.
 *
 * `width: 100%` gehoert zwingend dazu. Ohne eine bestimmte Breite nehmen die
 * automatischen Raender einem Rasterelement seine Streckung: Es faellt auf
 * seine **Inhaltsbreite** zurueck und stellt sich damit nach der laengsten
 * Zeile mittig - die Flucht haenge dann am Inhalt, eine lange Zeile schoebe
 * den ganzen Bereich nach links, eine kurze nach rechts. Genau der Fehler,
 * wegen dem hier einmal `margin: 0` stand.
 */
.bk-inhalt { margin: 0; max-width: none; padding: 1rem 0 0; min-width: 0; }

/* Das Backend geht mit, aber eine Stufe leiser: Hier steht kein Titel ueber
   einer Seite, sondern der Name einer Flaeche, an der man arbeitet. */
.bk-inhalt h1 { font-size: clamp(1.75rem, 3.4vw, 2.3rem); margin: 0 0 1.5rem; }
@media (min-width: 56rem) {
  /* **Every area starts below the bar at the top right, with a little room.**
     The bar is as wide as the name and the chosen entry in it; a heading
     that shared its row wrapped as soon as the window narrowed. Below it the
     heading has the full width at every size. */
  .bk-inhalt {
    padding-top: calc(var(--navheight, 3.7rem) + 1.5rem);
    width: 100%; max-width: 1640px;
    margin-left: auto; margin-right: auto;
  }
  /* A heading is a flex row so that the marks after the words - the help
     sign, a lock, the tier pill - sit at the foot of the line rather than
     stretched to its height, and wrap with the words on a narrow column. */
  .bk-inhalt h1 { display: flex; align-items: flex-end; flex-wrap: wrap; }
}
.bk-inhalt .lead { margin: 0 0 1.4rem; color: var(--soft); font-size: 1rem; max-width: var(--text); }
/* **Vor einer Tafel rueckt der Kopf naeher.** Der Abstand des Vorspanns und
   das Polster der Tafel stehen sonst uebereinander - 1,4 rem plus 1,25 sind
   zweieinhalb Zeilen Luft zwischen einem Satz und der Arbeit, die er
   ankuendigt. Einer von beiden gehoert weg, und das ist der aeussere: Das
   Polster ist die Form der Tafel, der Abstand nur die Vorgabe des Absatzes. */
.bk-inhalt .lead:has(+ .bk-tafel) { margin-bottom: .6rem; }

/* Die Zahlen der Uebersicht. Gross die Zahl, klein das Wort - man sucht hier
   die Zahl und liest das Wort erst zur Bestaetigung. */
.bk-zahlen {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 1px; background: var(--line);
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}
/* **`--card-ground` und nicht `--paper`.** Die Reihe steht auf der Tafel, und
   `--paper` ist im dunklen Backend derselbe Wert wie der Grund - die Zellen
   waeren dort dunkler als das Blatt, auf dem sie liegen. Was die Zellen
   trennt, ist ohnehin nicht ihre Farbe, sondern die `--line` des Containers,
   die durch die 1-px-Fuge scheint. */
.bk-zahlen li { background: var(--card-ground); padding: 1.1rem 1.2rem; }
.bk-zahl-gross { display: block; font-size: 2rem; font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.bk-zahl-wort { display: block; font-weight: 700; font-size: .95rem; margin-top: .2rem; }
.bk-zahl-zusatz { display: block; font-size: .82rem; color: var(--soft); margin-top: .1rem; }
/**
 * **Die Kurve steht vor der Zahl** (05.09.2026) - links von „791 Aufrufe",
 * genau wie vor dem Namen in „Beansprucht".
 *
 * Und es ist **dieselbe** Kurve: `.mini-kurve`, unveraendert, das Quadrat von
 * 36 Pixeln mit seinem hellen Grund. Hier stand einen Zug lang eine breite
 * Fassung ueber die ganze Kachel; damit haette dieselbe Abbildung zwei Masse
 * gehabt, je nachdem wo sie steht. Eine Grundlage, ein Mass - dann ist die
 * Linie an jeder Stelle im Backend dasselbe Zeichen.
 *
 * `flex-start`, weil die Zahl der Anker ist: 2 rem mal Zeilenhoehe 1,1 sind
 * 35 Pixel, das Quadrat 36 - oben buendig stehen beide auf einer Linie, und
 * Wort und Zusatz haengen darunter am Text, nicht an der Abbildung.
 */
/**
 * **Eine Leiste mit Kurven steht auf Grau** - die ganze, nicht die einzelne
 * Kachel darin.
 *
 * Der graue Grund sagt, welche **Sorte Leiste** man vor sich hat: gemessene
 * Werte ueber einen Zeitraum (Aufrufe, Anzeigen, gesuchte Begriffe) gegen einen
 * blossen Bestand (die vier unter „Einladungen", die keine Kurve haben). Und er
 * macht den hellen Kasten der Kurve **sichtbar** - darauf liest sich die Linie
 * als Abbildung und nicht als Strich, der in der Kachel liegt.
 *
 * **Je Kachel war es die falsche Stufe.** Unter „Was Google zeigt" haben zwei
 * von drei eine Kurve und die dritte („ohne Klick") nicht - sie zaehlt Zeilen
 * einer Liste, dafuer gibt es keinen Verlauf. Weiss zwischen zwei grauen
 * Kacheln liest sich aber nicht als „andere Sorte", sondern als Loch: Die drei
 * stehen nebeneinander, sind gleich hoch und beantworten dieselbe Frage in drei
 * Schnitten. Verglichen wird **in** der Leiste; also entscheidet die Leiste.
 *
 * `:has` fragt genau das - keine Klasse, die jemand mitschreiben muss.
 */
.bk-zahlen:has(.mini-kurve) li { background: var(--shade); }
/**
 * **Die Kachel hat zwei Zeilen**: oben Kurve und Zahl nebeneinander, darunter
 * der Zusatz ueber die ganze Breite.
 *
 * Der Zusatz steht damit **am linken Rand, unter der Kurve** und nicht neben
 * ihr eingerueckt: „in 30 Tagen" gilt fuer die Zahl **und** fuer die Linie.
 * Neben der Zahl haette er nur die Zahl erklaert.
 */
/**
 * **Hier ist das Quadrat so hoch wie Zahl und Wort zusammen** (05.09.2026).
 *
 * Es bleibt dieselbe Abbildung wie in „Beansprucht" - dieselbe Funktion,
 * derselbe Grund, dieselbe Rundung, und **quadratisch** bleibt es auch. Nur
 * das Mass kommt aus der Zeile, in der es steht: In der Liste ist das die
 * Zeilenhoehe (36 Pixel, so gross wie das Vorschaubild daneben), hier sind es
 * die zwei Zeilen daneben. Eine Abbildung, die neben einem Block steht und
 * nur halb so hoch ist wie er, sieht aus, als waere sie abgerutscht.
 *
 * **Warum eine gerechnete Zahl und kein `align-self: stretch`.** Genau das
 * stand hier zuerst, zusammen mit `aspect-ratio: 1` - und das Quadrat wurde
 * 412 Pixel gross. Ein `<svg>` mit `viewBox` ist ein **ersetztes** Element mit
 * eigenem Seitenverhaeltnis (hier 100:20); als Flex-Kind bestimmt es seine
 * Breite aus dem Platz, den es findet, und die Hoehe folgt daraus. Die
 * Rechnung lief also andersherum, als sie sollte.
 *
 * Deshalb steht die Hoehe hier als Summe der zwei Zeilen, aus **denselben
 * Werten**, die die zwei Zeilen setzen - und die Zeilenhoehe des Wortes ist
 * dafuer festgeschrieben statt geerbt: Sonst waere die Summe eine Schaetzung.
 */
.bk-zahl-kopf {
  display: flex; gap: .8rem;
  /* Zahl (2rem x 1,1) + Abstand (0,2rem) + Wort (0,95rem x 1,4). */
  --kopf-hoehe: calc(2rem * 1.1 + .2rem + .95rem * 1.4);
}
.bk-zahl-kachel .bk-zahl-wort { line-height: 1.4; }
.bk-zahl-kopf .mini-kurve {
  flex: none; width: var(--kopf-hoehe); height: var(--kopf-hoehe);
}
/* `min-width: 0`, damit ein langes Wort die Kachel nicht auseinanderdrueckt:
   In einem Grid ist die kleinste Breite eines Flex-Kindes sonst sein Inhalt. */
.bk-zahl-text { display: block; min-width: 0; }
/**
 * **Derselbe Abstand ueber dem Zusatz in der ganzen Leiste.**
 *
 * Er gehoert der Kachel **mit** Kurve (dort haengt der Zusatz unter dem
 * Quadrat, nicht neben ihm); mit .1 rem daneben sass der Zusatz einer Kachel
 * ohne Kurve zwei Millimeter hoeher als der ihrer Nachbarn - eine Stufe quer
 * durch eine Zeile, die nichts bedeutet. Die Kacheln sind ohnehin gleich hoch
 * (das Raster streckt sie); was sich unterscheiden darf, ist der Inhalt und
 * nicht sein Rhythmus.
 */
.bk-zahlen:has(.mini-kurve) .bk-zahl-zusatz { margin-top: .55rem; }

/* Verweise im Backend tragen die Schriftfarbe. Ohne diese Zeile stehen sie im
   Blau des Browsers - in einer Arbeitsansicht mit vielen Zeilen ist das ein
   Farbfleck je Zeile und keine Auskunft. */
.bk-inhalt a { color: var(--strong); text-decoration-thickness: 1px; text-underline-offset: .16em; }
.bk-inhalt a:hover, .bk-inhalt a:focus-visible { text-decoration-thickness: 2px; }

/* ==========================================================================
   DER EINTRAGSEDITOR - `#/eintrag/<slug>`
   ==========================================================================

   **Kein eigenes Formularsystem.** Die Felder sind `.feld`, `.feld-paar`,
   `.feld-haken`, die Knoepfe `.action`, die Zustaende `.konto-status` - alles
   schon da und in derselben Groesse. Was hier dazukommt, sind nur die drei
   Dinge, die es vorher nicht gab: der **Abschnitt** (eine Ueberschrift, Felder,
   ein Knopf), die **Zeitspanne** (sieben Tage und zwei Uhrzeiten in einer
   Zeile) und die **Bildzeile** (Foto links, Nachweis rechts).

   **Getrennt wird mit einer Linie, nicht mit einem Rahmen.** Zehn Abschnitte in
   zehn Kaesten waeren zehn Rahmen auf einer Seite, die sonst keine hat -
   `border-radius: 0` und Karten ohne Rahmen sind Marke (siehe Styleguide). */

.ed-kopf { margin: 0 0 2rem; }
/**
 * **Die Adresse steht in der Monospace** - sie ist keine Prosa, sondern ein
 * Pfad, und dort zaehlt jedes Zeichen einzeln: Ein Bindestrich zu viel im Slug
 * faellt in einer Proportionalschrift niemandem auf. Dieselbe Familie wie die
 * Kennung daneben, die Fassung am Fuss der Spalte und jedes `code` des Hauses.
 * Etwas kleiner (.82 rem), weil eine Monospace bei gleicher Punktzahl groesser
 * wirkt als die Grotesk daneben.
 */
/**
 * **Die Adresszeile steht nicht mehr im Kopf.**
 *
 * Sie trug Slug, Kennung und das Auge zur Vorschau - drei Angaben ueber die
 * Sache, die man beim **Bearbeiten** nicht braucht: Der Slug steht im Reiter
 * „URL", die Kennung ist eine Systemangabe, und die Vorschau steht in der
 * Liste an jeder Zeile. Der Kopf traegt damit nur noch Name und Zustand.
 *
 * Ausgeblendet und nicht entfernt: Die Zeile wird an vier Stellen gebaut, und
 * eine Regel ist ein Handgriff, vier Markups sind vier.
 */
.ed-adresse { display: none; }
.ed-adresse .pruef-von { margin-top: .1rem; }
/**
 * **Das Auge steht in der Zeile, nicht darueber.**
 *
 * Die Adresse ist Text, das Zeichen ist ein Kasten - nebeneinander gesetzt
 * sitzt es sonst auf der Grundlinie und haengt unter der Zeile. `vertical-align`
 * stellt es auf die Mitte der Ziffern, und `line-height: 0` nimmt ihm die
 * eigene Zeilenhoehe, die die Zeile sonst hoeher machte als die darunter.
 *
 * Grau wie jedes ruhende Zeichen des Hauses, schwarz beim Zeigen und im Fokus -
 * dieselbe Farbachse wie die Zeichen in der Bestandstabelle.
 */
/**
 * **Das Auge steht im Kopf, rechts neben dem Zustand.**
 *
 * Beide sagen etwas ueber die Sache als Ganzes - was sie gerade ist, und wie
 * sie aussieht. In der Zeile darunter stand es neben der Adresse, und die
 * braucht beim Bearbeiten niemand.
 *
 * Es ist ein Flexkind der Ueberschrift (`.ed-name`), sitzt also von selbst auf
 * ihrer Mitte - `vertical-align` traegt hier nichts mehr, es bleibt fuer den
 * Fall, dass es je wieder in einem Satz steht. Die Groesse haengt an der
 * Ueberschrift, nicht an einer festen Zahl: `1em` ist an einem `h1` von
 * 2,3 rem so gross wie der Name daneben zu ihm passt.
 */
.ed-vorschau {
  display: inline-block; vertical-align: -.22em; line-height: 0;
  margin-left: .15rem; color: var(--soft);
}
.ed-name .ed-vorschau { flex: none; margin-left: .1rem; }
.ed-vorschau svg { width: 1.1rem; height: 1.1rem; display: block; }
/* One size at every width: .92 rem is .4 of the heading at its full
   2.3 rem. In `em` it shrank with the heading's `clamp()` on a phone. */
.ed-name .ed-vorschau svg { width: .92rem; height: .92rem; }
.ed-vorschau:hover, .ed-vorschau:focus-visible { color: var(--strong); }
/* The sentence without PRO stands with room above and below - it is the
   first thing under the head, and the panel starts after it. */
#mappe-ohne-pro { margin: 1rem 0 1.25rem; }

/**
 * Ein Abschnitt: Luft darum, keine eigene Linie oben.
 *
 * Hier stand `border-top` - und darueber steht die Reiterleiste, die selbst
 * mit einer Linie abschliesst. Zwei Striche mit 27 px Nichts dazwischen, auf
 * jedem der zehn Abschnitte. **Die Leiste ist schon die Trennung.**
 * `.mein-block` setzt ihn genau aus diesem Grund seit jeher zurueck.
 */
/**
 * **Das Panel ist die Tafel des Editors.**
 *
 * Ein Editor bringt seinen Kopf mit - Rueckweg, Ueberschrift, Zustand,
 * Reiterleiste -, und der gehoert ueber das Papier wie auf jeder anderen
 * Seite, nicht darauf. Deshalb traegt der Abschnitt `data-ohne-tafel`, und die
 * Flaeche sitzt eine Ebene tiefer: **an dem, was der Reiter umschaltet.**
 *
 * Dieselben drei Token wie jede andere Tafel - es gibt im Backend eine Sorte
 * Papier. Der Abstand nach oben bleibt, die Lesebreite auch: Ein Formular ist
 * eine Spalte Text mit Feldern, und daran aendert der Grund darunter nichts.
 */
/* **The gap above belongs to the section navigation's frame**
   (`.abschnitt-rahmen`), not to the panel below it - two gaps on top of each
   other would be one too many. */
.ed-block, .ed-bilder, .ed-vorteile {
  margin: 0;
  display: grid; gap: 1rem; max-width: 46rem;
  background: var(--card-ground);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
  /* **Ringsum dasselbe Mass.** Oben stand 1,25 und an den Seiten 1,4 - ein
     Unterschied, den man einzeln nicht sieht und nebeneinander sofort. Eine
     Tafel hat vier Kanten und einen Rand. */
  padding: 1.4rem;
}
/* Was oben und unten in der Tafel steht, bringt seinen eigenen Aussenabstand
   mit - sonst laegen zwei Polster uebereinander, und zwar in jedem Panel ein
   anderes. Dieselbe Regel wie an `.bk-tafel`. */
.ed-block > :first-child,
.ed-bilder > :first-child,
.ed-vorteile > :first-child { margin-top: 0; }
.ed-block > :last-child,
.ed-bilder > :last-child,
.ed-vorteile > :last-child { margin-bottom: 0; }
.ed-titel { font-size: 1.15rem; margin: 0; }
.ed-titel .pruef-von { display: inline; font-weight: 400; margin-left: .4rem; }
/* **Kein Zug nach oben.** Die Erklaerung hing mit `-.4rem` an der Kante -
   ein Ausgleich fuer den Trennstrich, den `.konto-warum` damals nach oben
   zog. Den Strich gibt es nicht mehr, und in einer Tafel zog der Rest die
   erste Zeile naeher an den Rand als alles daneben. */
.ed-block .konto-warum, .ed-bilder .konto-warum, .ed-vorteile .konto-warum {
  margin-top: 0;
}
.ed-paar { gap: 1rem; }

/* ===========================================================================
   DIE TREFFERVORSCHAU - eine Nachbildung, und sie sagt es
   ===========================================================================

   **Hier stehen Fremdfarben, und das ist die dokumentierte Ausnahme.** Der
   Kasten bildet einen Google-Treffer nach - blauer Titel, graue Adresszeile,
   serifenlose Systemschrift -, weil „sieht das gut aus?" sich nur an etwas
   beantworten laesst, das aussieht wie das Original. Er liegt deshalb **in**
   der grauen Erklaerbox (`.ed-erklaerung`) und auf Papier: dieselbe Bauart wie
   das Vorteilsbeispiel - die Erklaerung grau, das Zitat darin hell. So
   behauptet er nicht, ein Bauteil des Guide zu sein.

   **Die Farben sind fest und nicht aus den Token.** Ein Google-Blau aus
   `--brand` waere kein Google-Blau mehr. Im Dunkelmodus nimmt der Kasten
   trotzdem ein helles Papier: Er zitiert eine Flaeche, die es nur hell gibt.

   **Und nur er.** Die Regel stand auf `.ed-beispiel` und traf damit beide
   Kaesten des Reiters - auch das breite Teilen-Bild darunter. Das zitiert
   nichts: WhatsApp, Slack und Signal haben alle drei einen Dunkelmodus. Der
   Satz darin steht in `--soft`, und `--soft` auf Weiss sind im Dunkelmodus
   2,6 : 1 - unlesbar genau in dem Zustand, in dem dieser Editor fast immer
   steht. Deshalb haengt das Weiss an `.serp`, der Marke der Nachbildung. */
.ed-treffer { display: grid; gap: 1rem; }
.ed-trefferbox .ed-beispiel { margin: .6rem 0 0; }
.ed-trefferbox .ed-beispiel.serp {
  background: #fff; color: #202124; padding: .9rem 1rem;
  border: 1px solid var(--line);
  font-family: arial, system-ui, sans-serif;
}
.serp-zeile { display: flex; gap: 1rem; align-items: flex-start; }
.serp-text { flex: 1; min-width: 0; }
.serp-pfad {
  margin: 0 0 .15rem; font-size: .75rem; color: #4d5156; overflow-wrap: anywhere;
}
.serp-zustand { margin-left: .5rem; font-style: italic; }
/* **Zwei Zeilen, dann ist Schluss** - die Form der Kuerzung, nicht eine
   Pixelrechnung: Google misst in seiner eigenen Schrift, die wir nicht haben.
   `anywhere` gegen ein Wort ohne Leerzeichen, das den Kasten auseinanderschoebe. */
.serp-titel {
  margin: 0; font-size: 1.1rem; line-height: 1.3; color: #1a0dab; font-weight: 400;
  overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.serp-satz {
  margin: .2rem 0 0; font-size: .82rem; line-height: 1.55; color: #4d5156;
  overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
/* Kein Warnton: Ein frischer Beitrag ohne Kurzbeschreibung ist der
   Normalzustand und kein Fehler. */
.serp-satz.is-leer { font-style: italic; }
/* **Das Quadrat rechts ist Googles Bild, nicht unseres** - es sucht es selbst
   aus der Seite. Hier steht das Kopfbild als Anmutung; der Satz darueber sagt,
   wem die Wahl gehoert. */
.serp-bild { flex: none; width: 5.5rem; aspect-ratio: 1; overflow: hidden; border-radius: 8px; }
.serp-bild img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 30rem) {
  .serp-bild { width: 4rem; }
}

/* Das Bild des geteilten Verweises: 1,91 : 1, mittig beschnitten - das Mass,
   das WhatsApp, Slack und Signal zeigen. */
.treffer-bild { aspect-ratio: 1.91; overflow: hidden; background: var(--shade); }
.treffer-bild img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Die gestrichelte Kante heisst im Haus „hier fehlt etwas" - dieselbe wie am
   Ablegefeld fuer Bilder. */
.treffer-bild.is-leer {
  border: 2px dashed var(--line); background: none; aspect-ratio: auto;
  display: grid; place-content: center; justify-items: center; gap: .5rem;
  text-align: center; padding: 1.2rem 1rem;
}
.treffer-bild.is-leer p { margin: 0; font-size: .85rem; color: var(--soft); }

/* Das Produkt traegt dieselbe Erklaerbox wie die Vorschau darueber - nur zu.
   Die Felder darin stehen auf Papier, damit sie sich vom Grau abheben. */
.ed-produkt .ed-aufklapp-inhalt { display: grid; gap: 1rem; }
.ed-produkt .feld input, .ed-produkt .feld textarea, .ed-produkt .feld select {
  background: var(--paper);
}
/**
 * **Öffnungszeiten und Bilder unter „Mein Eintrag"** (05.09.2026) - dieselbe
 * Form wie ein Abschnitt im Editor: Luft darum, kein Kasten.
 *
 * **Keine Ueberschrift darin und keine Linie darueber:** Der Reiter sagt
 * schon, was hier steht („Öffnungszeiten", „Bilder"), und ein zweites Mal
 * dasselbe Wort unter der Reiterleiste ist eine Zeile, die nichts hinzufuegt.
 * Die Trennung uebernimmt die Leiste - deshalb faellt der Strich weg, den
 * `.ed-block` von oben mitbringt.
 */
/* **Das Polster kommt von `.ed-block` und bleibt.** Hier stand `padding-top: 0`
   - der Ausgleich fuer einen Trennstrich, den es nicht mehr gibt. In einer
   Tafel nahm er dem Panel seine obere Kante, und die erste Zeile klebte am
   Rand, waehrend links, rechts und unten 1,4 rem standen. */
/**
 * **Die Tafel von „Mein Eintrag" ist dieselbe wie im Editor.**
 *
 * Vier der fuenf Flaechen sind ein `form` und tragen `.ed-block` mit; die
 * **Bilder** sind eine `section` und standen deshalb als einzige nackt auf dem
 * grauen Grund - derselbe Inhalt, zwei Aussehen, je nachdem welches Element
 * ihn traegt. Die Kachel haengt jetzt an `.mein-block` selbst; wo `.ed-block`
 * daneben steht, sind es dieselben drei Token und nicht zwei Kaesten.
 */
.mein-block {
  margin: 0; border-top: 0;
  display: grid; gap: 1rem; max-width: 46rem;
  background: var(--card-ground);
  border-radius: var(--card-radius);
  box-shadow: var(--card-shadow);
  padding: 1.4rem;
}
.mein-block > :first-child { margin-top: 0; }
.mein-block > :last-child { margin-bottom: 0; }
.mein-block .konto-warum { margin: 0; border-top: 0; }
.mein-block .konto-liste { list-style: none; margin: 0; padding: 0; display: grid; gap: .6rem; }

/* Die Antwort des Backends - an dem Knopf, der sie ausgeloest hat.

   Dieselben zwei Worte wie in der Meldezeile (`.count.gut`, `.count.fehler`):
   fett und in `--strong`, nicht gruen und rot. Der Satz selbst sagt, was
   passiert ist - eine Farbe, die es noch einmal sagt, sagt es nur denen, die
   sie sehen. */
/* `.ed-stand` ist weg (04.09.2026): Die Meldung neben dem Knopf sagte
   dasselbe wie die Leiste unten - „Gespeichert." zweimal auf einem Schirm. */

/* Die Gattungen: vier Kaesten, in jedem die Haken einer Kategorie. `legend`
   traegt den Namen der Kategorie - damit sagt ein Vorleseprogramm bei jedem
   Haken, in welcher Gruppe er steht. */
.ed-gattungen {
  border: 1px solid var(--line); padding: .8rem 1rem; margin: 0;
  display: grid; gap: .4rem; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}
/* Groesse und Staerke kommen aus der Beschriftungsregel; hier bleibt nur, was
   diesen Kasten angeht: die Luft, mit der das Wort den Rahmen unterbricht. */
.ed-gattungen legend { padding: 0 .3rem; }

/**
 * **EINE ZEITSPANNE IST EIN SATZ** (05.09.2026) - „Mo bis Fr, 12:00-16:00".
 *
 * Vorher standen hier sieben Ankreuzkaestchen je Zeile, also die Form, in der
 * Convex die Zeiten ablegt (`{days:[1,2], from, to}`). Wer werktags offen hat,
 * hakte fuenfmal an. Jetzt ist der Tagesteil ein **Bereich** aus zwei
 * Auswahlfeldern, und die Zeile liest sich, wie man sie vorliest.
 *
 * Auf dem Telefon stehen Tage und Uhrzeiten untereinander, das Kreuz rechts
 * daneben; ab 46rem ist es eine Zeile. Die zwei Blocks bleiben dabei jeweils
 * **zusammen** - „Mo bis" oben und „Fr" unten waere kein Satz mehr.
 */
/**
 * **Die Zeitenabschnitte greifen ueber die Lesebreite hinaus** (05.09.2026).
 *
 * `.ed-block` und `.mein-block` stehen auf 46 rem - richtig fuer ein Feld, das
 * man liest, und zu eng fuer eine Zeile mit sechs Feldern nebeneinander: Bei
 * genau 46 rem passte sie rechnerisch und brach in der Praxis um, sobald in
 * einer Auswahl „Donnerstag" stand.
 *
 * Dieselbe Bauart wie die Galerie auf `/merchandise/`: **Der Text bleibt in
 * der Lesespalte, nur der breite Teil greift darueber hinaus.** Deshalb zwei
 * Regeln - der Abschnitt wird breit, und alles darin ausser der Liste bekommt
 * die 46 rem zurueck. Ein Satz ueber 58 rem waere sonst hundert Zeichen lang.
 */
.ed-block:has(.ed-spannen), .mein-block:has(.ed-spannen) { max-width: 58rem; }
/* Die Linie unter der Liste ist so breit wie die Liste - sie ist ihr Ende,
   nicht ein Absatz darunter. */
.ed-block:has(.ed-spannen) > *:not(.ed-spannen):not(.zeilenlinie),
.mein-block:has(.ed-spannen) > *:not(.ed-spannen):not(.zeilenlinie) { max-width: 46rem; }

/* „Immer zugaenglich" blendet die Zeilen aus - sie gelten dann nicht. Verborgen
   und nicht geleert: Wer den Haken wieder herausnimmt, findet seine Woche. */
.ed-spannenteil[data-aus="ja"] { display: none; }

.ed-spannen { display: grid; }
/**
 * **Auf dem Telefon zwei Zeilen, nicht drei** (06.09.2026).
 *
 * Die beiden Tagesfelder standen auf `flex-wrap: wrap` mit `max-width: 9.5rem`
 * - zusammen mit „bis" und dem Kreuz passte das bei 390 px nicht, also brach
 * es um: „Montag ⌄ bis" oben, „Dienstag ⌄" darunter, die Uhrzeiten in einer
 * dritten. Das Wort „bis" hing dabei am Ende der ersten Zeile in der Luft, und
 * das Kreuz stand mittig neben einem Block, dessen Anfang und Ende es nicht
 * mehr beruehrte. Sechs Spannen waren so tausend Pixel.
 *
 * Jetzt ein Raster mit Namen: Tage oben ueber die ganze Breite, Uhrzeiten
 * unten, das Kreuz am Ende **der Zeile, die es entfernt**. Beide Haelften sind
 * innen `1fr auto 1fr` - die Felder teilen sich, was da ist, statt sich an
 * einer festen Breite zu stossen.
 */
.ed-spanne {
  display: grid; gap: .5rem .8rem; align-items: center;
  grid-template-columns: 1fr auto;
  grid-template-areas: "tage tage" "zeit kreuz";
  padding: .6rem 0; border-top: 1px solid var(--line);
}
/* **Kein Abschlussstrich an der letzten Zeile** (06.09.2026) - den zieht die
   Linie darunter, und die ist zugleich der Knopf. Zwei Striche uebereinander
   waeren zwei Enden derselben Liste. */
.ed-spanne > .ed-kreuz { grid-area: kreuz; }
.ed-spanntage { grid-area: tage; }
.ed-spannzeit { grid-area: zeit; }
.ed-spanntage, .ed-spannzeit {
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: .4rem;
}
.ed-spanntage select, .ed-spannzeit input[type=time] { min-width: 0; width: 100%; }
/* Das Wort zwischen den beiden Haelften einer Spanne - Tage wie Uhrzeiten. Es
   traegt die Angabe nicht, es verbindet sie: leiser als das, was daneben steht. */
.ed-bis { color: var(--soft); font-size: .9rem; }

@media (min-width: 46rem) {
  .ed-spanne { grid-template-columns: auto 1fr auto; grid-template-areas: none; }
  .ed-spanne > .ed-kreuz, .ed-spanntage, .ed-spannzeit { grid-area: auto; }
  .ed-spanntage, .ed-spannzeit { display: flex; }
  /* **Kein Umbruch, sobald der Platz da ist.** „Mo bis" oben und „Fr" unten
     ist kein Satz mehr - und eine Liste, in der die dritte Zeile zweizeilig
     ist, liest sich nicht als Liste. Feste Breiten statt `max-width`, damit
     alle Zeilen dieselben Spalten haben. */
  .ed-spanntage, .ed-spannzeit { flex-wrap: nowrap; }
  .ed-spanntage select { width: 9.5rem; flex: none; }
  .ed-spannzeit input[type=time] { width: 7.5rem; flex: none; }
  .ed-bis { white-space: nowrap; }
}

/* Die Woche als Rueckmeldung: kein Fehler, keine Warnfarbe - dieselbe leise
   Zeile wie ein Feldhinweis, direkt unter der Liste, auf die sie sich
   bezieht. */
.ed-zeitenwoche { margin: 0; font-size: .85rem; color: var(--soft); }

/**
 * **Was nicht zusammenpasst - an der Stelle, an der es entsteht.**
 *
 * Kein Kasten und keine Farbe: Ein Fehler steht fett in `--strong`, ein
 * Hinweis grau daneben, beides in derselben Zeilenform wie die Feldhinweise
 * darueber (dieselbe Regel wie in der Meldeleiste - der Satz sagt, was los
 * ist, eine Farbe sagte es nur denen, die sie sehen).
 */
.ed-warnliste { list-style: none; margin: 0; padding: 0; display: grid; gap: .3rem; }
.ed-warnliste li { font-size: .85rem; line-height: 1.4; }
.ed-warn-fehler { font-weight: 700; color: var(--strong); }
.ed-warn-fehler::before { content: "!  "; white-space: pre; }
.ed-warn-hinweis { color: var(--soft); }

/**
 * **Der Satz steht eingeklappt** - weil er das Raster abraeumt.
 *
 * „Zeiten als Satz" ist der dritte Weg und der seltene: Es gibt ihn fuer
 * Zeiten, die mit der Jahreszeit wechseln. Als gleichwertiges Feld neben der
 * Woche war er eine Einladung, hineinzuschreiben - und wer beides ausfuellt,
 * verliert beim Speichern die Woche. Eingeklappt ist er da und nicht im Weg;
 * steht schon ein Satz darin, geht das Fach von selbst auf (`open`).
 */
.ed-satzfach > summary {
  cursor: pointer; font-weight: 700; font-size: .9rem; padding: .3rem 0;
}
.ed-satzfach > summary:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
.ed-satzfach > .feld { margin-top: .6rem; }

.ed-merkmal {
  display: grid; gap: .6rem; padding: .8rem 0; border-top: 1px solid var(--line);
}

@media (min-width: 46rem) {
  .ed-merkmal { grid-template-columns: 1fr 1fr auto; align-items: center; }
}

/* Ein Knopf, der etwas wegnimmt, sieht nicht aus wie einer, der etwas tut:
   Schrift in `--soft`, und erst beim Zeigen wird er deutlich. Rot waere zu
   viel fuer „eine Zeile weniger" - der zweite Klick fragt ohnehin nach. */
/* Die Ablegeflaeche im Reiter „Bilder" - oben, mit Abstand zur Liste. */
/**
 * **Der Zustand steht neben dem Namen** (04.09.2026) - als Schild in der
 * Ueberschrift, nicht als Zeile darunter. Er hat dort die Groesse eines
 * Etiketts und nicht die der Ueberschrift: Er sagt etwas **ueber** den Namen,
 * er ist nicht Teil davon.
 */
.ed-name { display: flex; align-items: center; flex-wrap: wrap; gap: .7rem; }
/* **Both marks beside the name are built alike** - the tier pill and the
   status, in the editor head and in the search of the stock: monospace, the
   same size, the same padding. They are statements of
   the machine about the thing, and two sizes beside one name read as two
   different components. */
.ed-name .konto-status,
.ed-name .plan-pille,
.bestand-suche .konto-treffer .konto-status,
.bestand-suche .konto-treffer .plan-pille {
  font-family: var(--mono); font-size: .66rem; font-weight: 400; letter-spacing: .04em;
  line-height: 1.4; padding: .1rem .5rem;
}
/* The pill never stands alone on a line - joined to the name's last word by a
   non-breaking space in the markup (`editor.js kopf`), not by CSS: a flex
   child of `.ed-name` is blockified regardless of its own `display`, so an
   `inline` rule here would hold nothing together. */
/* The name is up to 2 rem high: the 2 px nudge of `.plan-pille` is set for
   running text and would let the pill hang below the middle of the letters.
   The non-breaking space before it is the gap, so its own margin shrinks. */
/* **The name is a row of its own, centred** - the words and the tier pill
   beside them, so the pill sits on the middle of the name like the status
   pill does in the heading row. `vertical-align: middle` put it on the middle
   of the lowercase letters, a few pixels below the status. The words wrap
   inside their own box; the pill stays beside them. */
.ed-name-wort { display: flex; align-items: center; gap: .7rem; min-width: 0; }
.ed-name-wort .plan-pille { flex: none; white-space: nowrap; margin-left: 0; }
/**
 * **The name of a thing carries its marks on its middle.** A heading in the
 * backend sets its marks at the foot of the line (`.bk-inhalt h1`); at a name
 * of 2.3 rem the status mark of .8 rem would sit well ten pixels too low
 * there, so the editor heads (`.ed-name`) put them in the middle again.
 */
.bk-inhalt h1.ed-name { align-items: center; }

/* Die Ablegeflaeche unter „Mein Eintrag" - dort traegt ein **Inhaber** ein Bild
   bei, und daran haengt die Rechtefrage (`BFPUpload.weg` mit `form: "ablage"`).
   Im Editor und am Beitrag steht sie als letzte Kachel des Rasters; die
   Redaktion laedt ueber `media.addAs` direkt frei hoch.

   `:not(:empty)`: Die Flaeche wird vom Bauteil gefuellt, und wer nicht
   beitragen darf, bekommt nichts hinein - ein leerer Kasten soll dann keinen
   Abstand aufspannen. */
.mein-block > #mein-bild-weg:not(:empty) { margin: 0 0 1.4rem; }
/* Die Beschriftung ueber der Flaeche - dieselbe Groesse wie jede andere
   Feldbeschriftung, sie kommt aus `.feld > span`. Hier nur der Abstand. */
.up-ablage { display: grid; gap: .35rem; }

/**
 * **Das Unwiderrufliche steht abgesetzt.** „Speichern", „Freigeben" und
 * „Entfernen" standen als drei Knoepfe gleichen Gewichts nebeneinander, und
 * einer davon hat keinen Rueckweg. `margin-left: auto` schiebt ihn an das
 * andere Ende der Reihe - erreichbar, aber nicht neben dem, was man oft tut.
 */
.ed-weg-knopf { color: var(--soft); margin-left: auto; }
/**
 * **Das Kreuz an einer Zeile** - Merkmal, Zeitspanne. Dasselbe Zeichen wie in
 * der Galerie und an jeder Schicht, in der Groesse eines Eingabefeldes daneben:
 * quadratisch, grau, beim Zeigen schwarz. Kein Rahmen - es sitzt am Ende einer
 * Zeile und nicht als Knopf in einer Reihe von Knoepfen.
 */
.ed-kreuz {
  flex: none; display: grid; place-items: center;
  /* 2,8 rem ist die Feldhoehe von oben - der Satz darueber stimmte bis heute
     nicht, das Kreuz war 2,2 rem und damit knapp einen halben Zentimeter
     niedriger als die Zeile, an deren Ende es steht (05.09.2026). Das Zeichen
     darin bleibt 1 rem; groesser wird nur die Flaeche, die man trifft. */
  width: 2.8rem; height: 2.8rem; padding: 0;
  border: 0; background: none; color: var(--soft); cursor: pointer;
}
/**
 * **DIE LINIE UNTER DER LISTE IST DER KNOPF** (06.09.2026).
 *
 * Erst stand hier „+ Spanne" als Knopf mit Wort, dann ein Plus in einem
 * Kasten - und darueber schloss die Liste mit einem Strich ab. Das waren zwei
 * Dinge fuer ein Ende: der Strich sagte „hier hoert die Liste auf", der Kasten
 * darunter „hier kommt die naechste Zeile". Jetzt ist es dasselbe Ding.
 *
 * **Getroffen wird die ganze Breite**, nicht das Zeichen: Der Knopf ist die
 * Linie, das Plus darauf ist seine Anzeige. Es erscheint beim Zeigen und beim
 * Fokus - `place-items` haelt es mittig, der eigene Grund deckt die Linie an
 * der Stelle ab, an der es steht.
 *
 * **Immer sichtbar in zwei Faellen**, und beide sind derselbe Gedanke - ein
 * Knopf, den niemand findet, ist keiner: ohne Zeigegeraet (Telefon, da gibt es
 * kein Zeigen) und bei **leerer** Liste (dann ist diese Linie das einzige, was
 * dasteht).
 */
/**
 * **Die Linie liegt auf der Oberkante des Knopfes** (06.09.2026), nicht in
 * seiner Mitte.
 *
 * Sie soll so dicht unter der letzten Zeile liegen wie jede andere Trennlinie
 * unter ihrer - und das sind die **.6 rem**, die eine Zeile selbst mitbringt
 * (`.ed-spanne { padding: .6rem 0 }`). Mittig im Knopf war sie 2,1 rem
 * entfernt; die letzte Zeile sass damit eng an ihrer oberen Linie und weit von
 * ihrer unteren.
 *
 * Auf der Oberkante liegt sie genau richtig, **ohne dass etwas nachgerechnet
 * werden muss**: Liste und Linie stehen zusammen in `.ed-spannenteil`, also
 * zwei Bloecke im normalen Fluss ohne Abstand dazwischen. Was der Knopf an
 * Hoehe hat, liegt **unter** der Linie, dort wo Platz sein darf.
 */
/**
 * **Zwei Listen, eine Linie** (07.09.2026). Sie hiess `.ed-spannlinie` und
 * gehoerte den Oeffnungszeiten; seit die Merkmale dieselbe Frage haben („wie
 * kommt eine Zeile dazu"), heisst sie nach der Sache und nicht nach dem ersten
 * Ort, an dem sie stand. Zwei Antworten auf dieselbe Frage in einem Editor
 * waeren zwei Bedienungen, die man einzeln lernt.
 *
 * Die Bedingung ist beide Male dieselbe: Liste und Linie liegen zusammen in
 * einem Block ohne `gap` (`.ed-spannenteil`, `.ed-listenteil`), damit die Linie
 * ohne Nachrechnen auf der Unterkante der letzten Zeile sitzt.
 */
.ed-listenteil { display: block; }
/* **Der Name traegt kein `ed-` mehr** (08.09.2026). Die Klasse hiess
   `.ed-zeilenlinie` - nach dem Editor, dem ersten Ort, an dem sie stand. Seit
   die Gliederung der Dokumentation dieselbe Linie benutzt (fuer eine neue Seite
   und fuer einen neuen Bereich), steht sie an **drei** Orten und heisst nicht
   mehr nach einem davon. Dieselbe Umbenennung wie `.ed-bild*` -> `.ed-zeile*`,
   und aus demselben Grund. */
.zeilenlinie {
  display: block; position: relative;
  width: 100%; height: 1.5rem; padding: 0;
  border: 0; border-top: 1px solid var(--line); background: none; cursor: pointer;
  /**
   * **Kein Abstand nach oben, und keiner zurueckzunehmen** (06.09.2026).
   *
   * Hier stand `margin-top: -1rem`, um den Abstand des **Blocks** aufzuheben:
   * Damals war die Linie ein eigenes Kind von `.ed-block`, und dessen `gap`
   * haette sie einen Zentimeter zu tief gesetzt. Seit „immer zugaenglich" die
   * Liste ausblendet, liegen Liste und Linie zusammen in `.ed-spannenteil` -
   * zwei Bloecke im normalen Fluss, **ohne** `gap`. Die Ruecknahme hob damit
   * nichts mehr auf, sondern zog die Linie einen Zentimeter nach oben: durch
   * die Auswahlfelder der letzten Zeile hindurch.
   *
   * Ohne sie sitzt der Strich genau an der Unterkante der letzten Zeile - also
   * .6 rem unter ihrem Inhalt, dieselben .6 rem wie ueber jeder anderen Zeile.
   */
}
/**
 * **Ein Plus im Kreis, sichtbar beim Zeigen** (06.09.2026).
 *
 * Vorher eine eckige Pille mit dem Wort „Zeitspanne hinzufuegen". Das Wort ist
 * weg, die Blende bleibt: Die Linie unter der Liste sagt schon selbst, dass die
 * Liste hier aufhoert - das Zeichen kommt dazu, wenn jemand hinfaehrt oder mit
 * der Tastatur ankommt, und ist sonst kein Fleck unter jeder Liste.
 *
 * **Ohne Zeigegeraet steht es immer da** - dort gibt es kein Zeigen, und ein
 * Knopf, den man nur durch Ausprobieren findet, ist keiner.
 *
 * Der Ring liegt in `--soft` und wird beim Zeigen und im Fokus `--strong` -
 * **exakt die Mechanik des Kreuzes am Zeilenende**: dasselbe Verhalten,
 * dasselbe Gewicht, an beiden Enden derselben Liste. (`--line` waere zu wenig:
 * 1,2 : 1 gegen `--paper`, und ohne Wort daneben ist der Ring die einzige
 * Anzeige.)
 *
 * **Die runde Ecke ist eine Ausnahme von `border-radius: 0`** - die vierte im
 * Haus, neben Suchschlitz, Profilbild und Telefonrahmen, und sie gilt nur hier.
 * Der Grund ist die Aussage der Form: Auf einer Linie ist ein Quadrat ein
 * **zweites** Element, ein Kreis ein Knoten **in** der Linie. Genau das ist der
 * Gedanke, wegen dem diese Linie selbst der Knopf ist.
 *
 * **Der Kreis ist die Anzeige, nicht das Ziel.** Getroffen wird die ganze
 * Breite der Linie (und ohne Zeigegeraet ihre 2,75 rem) - wer den Knopf je auf
 * Kreisgroesse zusammenzieht, reisst die Trefflaeche ein.
 */
.linieplus {
  position: absolute; left: 50%; top: 0; transform: translate(-50%, -50%);
  display: grid; place-items: center;
  /**
   * **1,25 rem, und die Grenze ist gerechnet, nicht geraten** (08.09.2026 auf
   * Wunsch von 1,05 heraufgesetzt).
   *
   * Hier stand „hoeher darf er nie" - das war die Zahl, nicht die Regel. Die
   * Regel: Der Kreis sitzt mittig **auf** der Linie, seine obere Haelfte ragt
   * also in die letzte Zeile hinein, und der Platz dort ist deren
   * Innenabstand (`.ed-spanne { padding: .6rem 0 }`, also 9,6 px).
   *
   *   1,25 rem = 20 px  ->  halbe Hoehe 10 px  ->  0,4 px ueber den Abstand
   *
   * Vier Zehntel Pixel Leerraum, kein Text. **Bei 1,5 rem waeren es 2,4 px** -
   * dann liegt der Ring auf der Kante des Auswahlfeldes, und das ist die
   * Grenze. Ein Halo oder ein Wachsen **ueber** die Endgroesse bleibt deshalb
   * verboten; die Einblende waechst von .82 auf 1 und nicht darueber hinaus.
   */
  width: 1.25rem; height: 1.25rem; padding: 0;
  border: 1px solid var(--soft); border-radius: 50%;
  color: var(--soft);
  /**
   * **Ein Verlauf, kein Schatten** (08.09.2026, auf Wunsch).
   *
   * `border-radius: 0` und „keine Schatten als Zierde" sind Hausregeln; ein
   * Schatten unter dem Kreis waere genau das. Ein Verlauf **im** Kreis ist
   * etwas anderes: Er gibt der Flaeche eine Richtung - oben heller, unten der
   * Ton der Kachel -, und der Kreis wirkt damit wie ein Knopf und nicht wie
   * ein Loch in der Linie.
   *
   * **Aus Token, nicht aus Hexwerten:** `--paper` nach `--shade`. Damit stimmt
   * er im Dunkeln von selbst - dort ist `--shade` heller als `--paper`, der
   * Verlauf dreht sich also mit und bleibt eine Woelbung.
   */
  background: linear-gradient(to bottom, var(--paper), var(--shade));
  /**
   * **Die Einblende ist kurz und kommt von unten aus dem Nichts** - opacity
   * plus ein Wachsen von .82 auf 1.
   *
   * `scale` **unter** 1 und nicht darueber: Der Kreis sitzt mittig auf der
   * Linie, seine obere Haelfte ragt in die letzte Zeile hinein, und dort ist
   * der Platz genau deren Innenabstand (.6 rem). Was ueber die Endgroesse
   * hinauswaechst, laege ueber den Feldern der Zeile - deshalb steht im
   * Kommentar oben „kein Wachsen beim Zeigen", und deshalb gilt das weiter
   * fuer alles **ueber** 1.
   *
   * 160 ms: kurz genug, dass es sich nicht wie eine Wartezeit anfuehlt, lang
   * genug, dass man es als Bewegung sieht und nicht als Sprung.
   */
  opacity: 0; transform: translate(-50%, -50%) scale(.82);
  transition: opacity .16s ease, transform .16s ease, border-color .12s ease,
    color .12s ease;
}
/* **Das Zeichen fuellt den Ring zu gut der Haelfte.** Das Lucide-Plus nutzt nur
   58 % seiner viewBox; bei .8rem waeren die Arme 7,5 px in einem 17-px-Kreis -
   ein Punkt mit Ring, kein Plus. Der Ring ist der Grund, warum es mitwaechst
   und mitschrumpft: Das Verhaeltnis bleibt, die Groesse aendert sich - mit dem
   Kreis auf 1,25 rem also das Zeichen auf 1,1 rem. */
.linieplus svg { width: 1.1rem; height: 1.1rem; flex: none; display: block; }
/**
 * **Keine zweite Form fuer die leere Liste.** Erwogen war, dort das Wort stehen
 * zu lassen - als Pille, weil ein Kreis allein nicht sagt, was als Erstes zu
 * tun ist. Es gibt diesen Zustand beim Oeffnen aber nicht: `zeilenAusSpannen`
 * gibt **immer** mindestens eine Zeile zurueck (`{ von: 1, bis: 7 }` mit leeren
 * Uhrzeiten), also steht ueber der Linie immer eine Zeile, die den Knopf
 * erklaert. Leer wird die Liste nur, wenn jemand die letzte Zeile mit dem
 * Kreuz wegnimmt - und der hat den Knopf gerade noch benutzt.
 *
 * Deshalb eine Form, ein Zustand, keine Sonderregel. Was das Wort trug, traegt
 * der Name am Knopf (`aria-label` und `title`).
 */
.zeilenlinie:hover .linieplus,
.zeilenlinie:focus-visible .linieplus {
  /* **Die Verschiebung muss mit.** `transform` ist eine Eigenschaft, nicht
     zwei: Stuende hier nur `scale(1)`, fiele `translate(-50%, -50%)` weg und
     der Kreis sprang aus der Mitte der Linie nach rechts unten. */
  opacity: 1; transform: translate(-50%, -50%) scale(1);
  border-color: var(--strong); color: var(--strong);
}
.zeilenlinie:hover, .zeilenlinie:focus-visible { border-top-color: var(--strong); }
/* Der Rahmen des Knopfes ist die Linie - ein zweiter Umriss darum herum
   zeichnete ein Rechteck, das es nicht gibt. Sichtbar wird der Fokus am Plus
   und an der Linie, die beide dunkler werden. */
.zeilenlinie:focus-visible { outline: none; }
@media (hover: none) {
  /* Kein Zeigen, also keine Blende - sonst gaebe es das Zeichen dort nie. Und
     dann auch in Endgroesse: Eine Einblende, die nie ausgeloest wird, liesse
     den Kreis dauerhaft auf .82 stehen. */
  .linieplus { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  /* **44 px fuer den Daumen.** Ohne Zeigegeraet ist die Linie die einzige
     Stelle, an der eine Zeile entsteht - 1,5 rem sind dafuer ein Strich, den
     man trifft oder auch nicht. Der Kreis bleibt mittig **auf** der Linie
     (`top: 0`), der Zuwachs geht nach unten. */
  .zeilenlinie { height: 2.75rem; }
}
/* Das Haus hat drei solcher Regeln - hier steht die vierte, aus demselben
   Grund: Ein Einblenden ist eine Bewegung. Sichtbar wird das Plus trotzdem,
   nur eben sofort. */
@media (prefers-reduced-motion: reduce) {
  /* **Ohne Uebergang, und in Endgroesse.** `transition: none` allein liesse den
     Kreis beim Erscheinen auf .82 stehen und ihn dann springen - eine
     abgeschaltete Bewegung ist keine, keine halbe. */
  .linieplus { transition: none; transform: translate(-50%, -50%) scale(1); }
}

.ed-kreuz:hover { color: var(--strong); }
.ed-kreuz:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
.ed-kreuz svg { width: 1rem; height: 1rem; }

/* Eine Bildzeile: das Foto links, der Nachweis rechts. Das Foto ist die
   Auskunft, die man zuerst braucht - „© Donauquelle" unter einer eigenen
   Aufnahme erkennt nur, wer das Bild dabei sieht. */
/**
 * **EINE BILDZEILE** (06.09.2026) - zu, bis man sie braucht.
 *
 * Vorher stand jedes Bild als offenes Formular da: Vorschaubild links, acht
 * Felder rechts, vier Knoepfe darunter. Bei fuenf Bildern vierzig Eingaben
 * untereinander, alle gleich laut. Jetzt eine Zeile, und darin genau das, was
 * man von aussen wissen muss: das Bild, **der fertige Nachweis**, die Datei -
 * und, nur wenn es einen gibt, der Mangel.
 */
/**
 * **Der Abschnitt wird breit, der Text bleibt in der Lesespalte.**
 *
 * Dieselben zwei Regeln wie bei den Zeiten (`.ed-block:has(.ed-spannen)`) und
 * wie die Galerie auf `/merchandise/`. Die 58 rem standen vorher an der Liste
 * selbst - und wirkten nicht: `.ed-bilder` deckelt bei 46 rem, also war die
 * Liste 736 px breit statt 928. Die Bildzeile braucht die Breite mehr als
 * jede andere: Bild, Nachweis, Dateiname und der Mangel nebeneinander.
 */
/**
 * **Alles im Reiter geht auf die Breite der Liste** (07.09.2026).
 *
 * Hier stand die Regel aus den Oeffnungszeiten: Abschnitt breit, alles darin
 * ausser der Liste zurueck auf 46 rem, „damit der Text in der Lesespalte
 * bleibt". Bei den Zeiten stimmt das - dort ist der Abschnitt selbst 46 rem
 * breit und nur die Zeilenliste greift darueber hinaus. Hier war es umgekehrt:
 * Die Liste ist 58 rem, also endeten Zaehler, Infobox und Ablegeflaeche
 * **zwoelf Zentimeter** vor der rechten Kante der Zeilen darunter - eine Stufe
 * mitten im Reiter, ohne dass sie etwas bedeutet.
 *
 * Die Lesespalte ist damit nicht aufgegeben, sie sitzt nur eine Ebene tiefer:
 * Der **Kasten** der Infobox geht auf die volle Breite, seine **Absaetze**
 * bleiben bei `--text`. Ein Rahmen ist eine Kante, ein Satz ist eine Zeile -
 * das sind zwei Fragen, und vorher hatten sie eine Antwort.
 */
.ed-bilder:has(.ed-zeilenliste) { max-width: 58rem; }
.ed-bilder .ed-aufklapp-inhalt > * { max-width: var(--text); }
.ed-zeilenliste { list-style: none; margin: 0; padding: 0; }

/**
 * **EIN AUFKLAPPER** (07.09.2026) - Chevron statt Dreieck.
 *
 * Das Dreieck, das der Browser an ein `<details>` malt, war das einzige
 * Zeichen im Haus, das nicht aus unserem Vorrat kommt: Navigation, Bildzeile
 * und Vorteilszeile zeigen alle denselben **Chevron**, wenn sich etwas
 * oeffnet. Deshalb ist es abgeschaltet (zweimal - `list-style` fuer die
 * Norm, `::-webkit-details-marker` fuer aeltere WebKits) und der Chevron steht
 * im Markup, wie ueberall sonst auch.
 *
 * Das Wort ist **halbfett und in Textfarbe**: Es ist die Zeile, auf die man
 * klickt, und stand vorher im selben Ton wie der Text darin.
 */
.ed-aufklapp > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: .5rem;
  font-weight: 600; color: var(--ink);
}
.ed-aufklapp > summary::-webkit-details-marker { display: none; }
.ed-aufklapp > summary:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
/* Derselbe Dreh wie an der Bild- und der Vorteilszeile: nach rechts, offen
   nach unten. Ohne Uebergang - die anderen beiden haben auch keinen. */
.ed-aufklapp-pfeil { display: grid; place-items: center; color: var(--soft); flex: none; }
.ed-aufklapp-pfeil svg { width: .9rem; height: .9rem; transform: rotate(-90deg); }
.ed-aufklapp[open] > summary .ed-aufklapp-pfeil svg { transform: none; }
.ed-aufklapp-inhalt { font-size: .9rem; color: var(--soft); }
.ed-aufklapp-inhalt > * { margin: .6rem 0 0; }

/**
 * **Die Erklaerung ist ein Kasten** - die Primärbildregel und „Was ein guter
 * Vorteil ist". Sie steht zwischen dem Zaehler und der Arbeit und war dort
 * eine Zeile unter vielen; ein Rahmen macht daraus etwas, das man einmal
 * aufmacht und danach uebersieht.
 *
 * **Die runden Ecken sind eine Ausnahme von `border-radius: 0`** - die fuenfte
 * im Haus, neben Suchschlitz, Profilbild, Telefonrahmen und dem Plus auf der
 * Zeilenlinie. Sie ist ausdruecklich gewuenscht und gilt nur fuer dieses
 * Bauteil: 4px, gerade so viel, dass der Kasten als **Beiwerk** liest und
 * nicht als Formularfeld.
 */
/**
 * **Sie muss sich vom Vorteil unterscheiden, den sie erklaert** (07.09.2026) -
 * sonst ist ein Kasten mit einem Satz darin dasselbe wie der Kasten mit dem
 * Satz, den der Gast liest, und man verwechselt beides. Drei Unterschiede,
 * alle gegen den Gastkasten (`.vorteil`) gerichtet:
 *
 * 1. Ein **Fragezeichen** statt des Geschenks - Lucide `circle-help`, das
 *    Zeichen der Hilfe im Haus (und ausdruecklich nicht das ⓘ, das dem
 *    Bildnachweis gehoert).
 * 2. **Kein Balken links.** Der ist die Signatur des Vorteils - genau die
 *    Aehnlichkeit, die hier weg muss.
 * 3. **Immer grauer Grund**, nicht erst aufgeklappt: Der Gastkasten liegt auf
 *    einer Ahnung von `--strong`, diese hier auf `--shade`. Zwei Flaechen, zwei
 *    Toene, auch geschlossen.
 */
.ed-erklaerung {
  border: 1px solid var(--line); border-radius: 4px;
  padding: .7rem .9rem; font-size: .9rem; color: var(--soft);
  background: var(--shade);
}
.ed-infozeichen { display: grid; place-items: center; color: var(--strong); flex: none; }
.ed-infozeichen svg { width: 1rem; height: 1rem; }
/* Das Beispiel darin: derselbe Gastkasten, auf hellem Grund, damit er sich vom
   Grau der Infobox abhebt - er ist das Zitat, nicht der Kasten. */
.ed-beispielwort { color: var(--soft); }
.ed-beispiel .vorteil { background: var(--paper); margin: 0; max-width: none; }
/* Der Verweis auf die Vorschau steht als letzte Zeile in der Infobox: Die
   Erklaerung sagt, was ein guter Vorteil ist, dahinter kommt der Blick auf die
   eigenen. */
/**
 * ===========================================================================
 * **DER LANGTEXT: FELD ODER ANSICHT**
 * ===========================================================================
 *
 * Kopfzeile mit Namen links und Regler rechts - dieselbe Aufteilung wie in
 * jeder Kopfzeile im Haus (Name links, Handlung rechts). Die Beschriftung ist
 * damit **nicht** mehr das `<span>` im Label, sondern die Zeile darueber; im
 * Label steht sie `visually-hidden` weiter, weil ein Feld seinen Namen braucht.
 *
 * **Feld und Ansicht sind gleich hoch gedeckelt**, damit der Block beim
 * Umschalten nicht springt: Die Ansicht eines 20-KB-Textes waere sonst
 * fuenfzehn Bildschirme, und der Regler waere nach dem ersten Klick nicht mehr
 * zu sehen. Sie rollt in sich - dieselbe Entscheidung wie bei der Schicht, in
 * der nur der Inhalt rollt und der Ausgang stehen bleibt.
 */
.ed-langtext { display: grid; gap: .45rem; }
.ed-langtext-kopf {
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; gap: .5rem;
}
.ed-langtext-wort { font-size: .9rem; color: var(--soft); }
.ed-langtext .feld { margin: 0; }
.ed-langtext-schau {
  max-height: 32rem; overflow-y: auto;
  border: 1px solid var(--line); padding: 1rem 1.1rem;
}
/* Der erste Abschnitt braucht oben keinen Abstand - der Rahmen gibt ihn. */
.ed-langtext-schau > :first-child { margin-top: 0; }
.ed-langtext-schau > :last-child { margin-bottom: 0; }
/**
 * **Die Legende ist eine Zeile, die man beim Tippen im Auge hat** - also
 * bricht sie um statt zu rollen, und die Beispiele haben Luft dazwischen. Sie
 * liegt eine Stufe leiser als der Hinweis darunter: Was immer gilt, muss nicht
 * lauter sein als das, was diese Seite dazu sagt.
 */
.ed-langtext-legende {
  display: flex; flex-wrap: wrap; gap: .2rem .55rem;
  margin-top: .1rem; font-size: .8rem;
}
.ed-langtext-legende code { font-size: .95em; }
/* Die Vorschauschicht: der Gastkasten, so wie er draussen steht. */
.vorteilschau .vorteil { margin: 0; max-width: none; }
/**
 * **Eine Feldergruppe im Formular** - „Code und Zeitraum", mit der Ueberschrift
 * ueber den Feldern, zu denen sie gehoert.
 *
 * Sie war ein Aufklapper (07.09.2026, am selben Tag wieder aufgemacht): Ein
 * Feld, das man erst aufklappen muss, ist ein Feld, von dem man nicht weiss,
 * dass es existiert - und der **Zeitraum** ist die Zusage, mit der dieser
 * Reiter wirbt („verschwindet von selbst").
 *
 * `min-width: 0` ist Pflicht an jedem `fieldset`, das etwas Schmales enthaelt:
 * Ohne die Angabe nimmt es die **groesste** Mindestbreite seines Inhalts an und
 * laesst sich nicht kleiner rechnen - auf dem Telefon schiebt es sonst die
 * ganze Zeile quer.
 */
.ed-gruppe { border: 0; padding: 0; margin: 0; min-width: 0; }
.ed-gruppe > legend {
  padding: 0; margin: 0 0 .6rem;
  font-size: .95rem; font-weight: 600; color: var(--ink);
}
.ed-gruppe > *:not(legend) { margin-top: 1rem; }
/* Das erste Feld schliesst direkt an die Ueberschrift an - ihr eigener
   Abstand nach unten reicht. */
.ed-gruppe > legend + * { margin-top: 0; }
.ed-zeile { border-top: 1px solid var(--line); }
.ed-zeile:last-child { border-bottom: 1px solid var(--line); }

/* Die Kopfzeile: der Aufklapper nimmt die Breite, der Stern sitzt am Rand.
   Zwei Knoepfe nebeneinander und nicht ineinander - ein `button` in einem
   `button` gibt es nicht, und der Stern ist ohnehin eine Wahl und kein Weg. */
.ed-zeilenkopf { display: flex; align-items: center; gap: .5rem; }
/**
 * **Vier Felder, benannt** - Pfeil, Bild, Wort, Mangel.
 *
 * Vorher fuenf Spalten mit zwei `auto` am Ende (Zustand, Punkte): Die beiden
 * nahmen sich ihre volle Breite, `minmax(0, 1fr)` gab bis auf null nach. Auf
 * dem Telefon blieb vom Namen `rave…` und vom Nachweis `© M…`, in neun
 * gleichen Zeilen - die Datei, die man sucht, war nicht zu finden.
 *
 * Jetzt bricht der Mangel auf dem Telefon in eine zweite Reihe und faellt
 * ganz weg, wenn es keinen gibt (`:not(:has(...))` - sonst bliebe eine leere
 * Reihe samt ihrem Abstand stehen).
 */
/**
 * **Drei Felder: Pfeil, Wort, Mangel.**
 *
 * Die Zieharmonika traegt die Vorteile und die Fragen eines Eintrags - Listen
 * aus **Saetzen**. Die **Bilder** haben sie am 09.09.2026 verlassen: Bei einem
 * Bild ist das Bild die Auskunft, und eine Zeile zeigt einen Daumennagel neben
 * sechs Zentimetern Text. Sie stehen jetzt als Raster (`.ed-bildraster`), und
 * mit ihnen ist die Bildspalte hier weggefallen.
 *
 * Die Mangelspalte bleibt: Dort steht ein Zustandswort, und ohne eines faellt
 * die Reihe ganz weg (`:not(:has(...))` - sonst bliebe ihr Abstand stehen).
 */
.ed-zeileauf {
  flex: 1; min-width: 0;
  display: grid; column-gap: .8rem; row-gap: .3rem; align-items: center;
  grid-template-columns: 1.2rem minmax(0, 1fr);
  grid-template-areas: "pfeil wort" ". mangel";
  padding: .6rem .2rem; border: 0; background: none; cursor: pointer; text-align: left;
}
.ed-zeileauf:not(:has(.ed-zeilemangel)) { grid-template-areas: "pfeil wort"; }
@media (min-width: 46rem) {
  .ed-zeileauf {
    grid-template-columns: 1.2rem minmax(0, 1fr) 8rem;
    grid-template-areas: "pfeil wort mangel";
  }
  .ed-zeileauf:not(:has(.ed-zeilemangel)) {
    grid-template-columns: 1.2rem minmax(0, 1fr);
    grid-template-areas: "pfeil wort";
  }
}
/**
 * **Die Zeile faerbt sich, nicht der Knopf.** Der Knopf endet vor dem Stern:
 * Beim Zeigen fuellte sich die Zeile bis kurz vor Schluss, dann kam ein weisser
 * Streifen und dann der Stern - und der Fokusrahmen umschloss die Zeile
 * **ohne** ihn, wie ein Kasten, den jemand zu kurz gezogen hat.
 *
 * `--shade` statt `--line`: `--line` ist der Ton der Trennstriche, und im
 * Dunklen (#2a3237 auf #12161a) war er vom Grund kaum zu unterscheiden.
 */
/* Auf der **Kopfzeile**, nicht auf der ganzen `li`: Die traegt bei offener
   Zeile auch das Formular, und ein Rahmen darum waere ein Kasten um eine
   halbe Seite. `.ed-zeilenkopf` ist genau Knopf plus Stern. */
.ed-zeilenkopf:has(.ed-zeileauf:hover) { background: var(--shade); }
.ed-zeilenkopf:has(.ed-zeileauf:focus-visible) {
  outline: 2px solid var(--strong); outline-offset: -2px;
}
/* Sonst zeichnet der Browser seinen eigenen Ring **zusaetzlich** - zwei
   Rahmen ineinander, einer davon in seiner Farbe und nicht in unserer. */
.ed-zeileauf:focus-visible { outline: none; }
/* Der Pfeil zeigt nach rechts und dreht sich beim Oeffnen nach unten -
   dieselbe Bewegung wie im Aufklapper der Navigation. */
.ed-zeilepfeil { grid-area: pfeil; display: grid; place-items: center; color: var(--soft); }
.ed-zeilepfeil svg { width: .9rem; height: .9rem; transform: rotate(-90deg); }
.ed-zeile[data-offen] .ed-zeilepfeil svg { transform: none; }
.ed-zeilewort { grid-area: wort; min-width: 0; display: grid; gap: .15rem; }
/* **Der Nachweis, wie er unter dem Foto steht** - jetzt die erste Zeile. Er
   ist die eigentliche Kontrolle: Der Anlass fuer diesen Editor war
   „© Donauquelle" unter drei eigenen Aufnahmen, und genau das liest man hier,
   ohne etwas zu oeffnen. */
.ed-bildnachweis {
  font-size: .92rem; font-weight: 700; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/**
 * **Auf dem Telefon bricht der Nachweis um, statt zu kuerzen.** Bei 390 px
 * blieb sonst „© Manuel Molicki · …" stehen - der Name war da, die
 * Rechtegrundlage abgeschnitten, und die ist der Teil, wegen dem die Zeile
 * existiert. Die Kantenlaenge faellt dort weg (dieselbe Entscheidung wie bei
 * den drei Punkten der Bestandstabelle): Sie ist eine Beigabe, der Dateiname
 * die Unterscheidung.
 */
@media (max-width: 45.99rem) {
  .ed-bildnachweis { white-space: normal; overflow: visible; }
}

/* Steht nur da, wenn etwas zu tun ist. Der Zustand nur, wenn er nicht
   „online" ist - neun gruene Kaestchen untereinander sind keine Auskunft. */
.ed-zeilemangel {
  grid-area: mangel; display: flex; flex-wrap: wrap; align-items: center; gap: .4rem;
}
.ed-zeilefehlt { font-size: .82rem; color: var(--soft); }

/**
 * **Der Stern ist die Wahl des Primärbilds** - einer je Zeile, eine Gruppe.
 * Gefuellt an dem einen, das es ist; gesperrt, wo es nicht geht, mit dem Grund
 * im `title`. Ein Knopf „Zum Primärbild machen" in **jeder** Zeile sagte, es sei
 * eine Handlung an einem Bild - es ist eine Wahl unter allen.
 */
.ed-stern {
  flex: none; display: grid; place-items: center;
  width: 1.9rem; height: 1.9rem; cursor: pointer; color: var(--soft);
}
/* **Das Zeichen sass 7 px zu hoch.** Der Griff traegt sein SVG als eigenes
   Rasterkind und stand damit genau mittig; der Stern haelt es in einem `span`,
   und ein inline gesetztes SVG steht auf der Schriftlinie - unter ihm blieb
   der Platz fuer die Unterlaengen stehen. `display: block` nimmt es aus der
   Zeile, dann ist die Hoehe des `span` die Hoehe des Zeichens. Fuer beide
   gesetzt, damit es eine Regel bleibt und keine zwei. */
.ed-stern svg,
.ed-bildkachel-griff svg { display: block; }
.ed-stern svg { width: .95rem; height: .95rem; }
.ed-stern:hover { color: var(--strong); }
.ed-stern-an { color: var(--strong); }
.ed-stern-an svg { fill: currentColor; }
/* Gesperrt ist kein blasser Stern, sondern ein anderes Zeichen - der
   Unterschied liegt in der Form, nicht im Tonwert (siehe `bildBlock`). */
.ed-stern-aus { cursor: help; color: var(--soft); }
.ed-stern:has(:focus-visible) { outline: 2px solid var(--strong); outline-offset: -2px; }

/**
 * Der aufgeklappte Teil: das Bild links, die Felder rechts. Das Foto ist die
 * Auskunft, die man zuerst braucht - „© Donauquelle" unter einer eigenen
 * Aufnahme erkennt nur, wer das Bild dabei sieht.
 *
 * **Er stand links neben seiner eigenen Zeile.** Der Einzug setzt ihn auf die
 * **Bildkante** darueber - Pfeilspalte plus die zwei Abstaende, mehr nicht.
 * Auf die Textkante ausgerichtet waeren es 100 px mehr, und die fehlen auf
 * einem Telefon dem Formular. Die Bildkante ist ohnehin der linke Anschlag der
 * Zeile: Der Pfeil ist Wegweisung, alles danach ist Inhalt. Der Balken links
 * bindet den Teil an die Zeile, zu der er gehoert.
 *
 * Der Grund ist eine **Flaeche**, wo sonst nur Linien trennen - und das ist
 * Absicht: Er markiert keine Trennung, sondern einen **Zustand** (offen).
 * Dasselbe Argument wie bei `.bk-zahlen-wahl button[aria-pressed="true"]`.
 */
/* Der Balken liegt auf **beiden** Teilen: Der Grund des Formulars uebermalt
   einen Schatten der `li`, und der Balken haette an der Kopfzeile aufgehoert -
   genau dort, wo er die Verbindung nach unten zeigen soll. */
.ed-zeile[data-offen] > .ed-zeilenkopf,
.ed-zeile[data-offen] > .ed-zeileform { box-shadow: inset 3px 0 0 var(--strong); }
.ed-zeileform {
  display: grid; gap: 1.2rem;
  background: var(--shade);
  /* .2rem Innenabstand des Knopfes + 1.2rem Pfeilspalte + .8rem Spaltenabstand
     - dieselbe Rechnung auf jeder Breite, weil nur die Bildspalte mitwaechst. */
  padding: 1rem 1rem 1.6rem calc(.2rem + 1.2rem + .8rem);
}
@media (min-width: 46rem) {
  /* Zwei Spalten nur, wo links ein Foto steht. Die Vorteilszeile hat keines -
     ihre Felder laufen durch. */
  .ed-zeileform:has(.ed-bildschau) { grid-template-columns: 18rem 1fr; }
}
.ed-bildfelder { display: grid; gap: 1rem; min-width: 0; align-content: start; }

/**
 * **Der Ausschnitt wird geklickt, nicht getippt.**
 *
 * Er stand als Textfeld da, in das man „50% 35%" schrieb - eine Koordinate,
 * von Hand geschaetzt, neben einem Bild, das die Antwort zeigt. Dieselbe
 * Entscheidung wie beim Pin in den Kerndaten: Was auf dem Schirm steht, zeigt
 * man an. Gespeichert wird dabei nichts; der Klick fuellt das Feld.
 */
.ed-schnitt { position: relative; cursor: crosshair; }
.ed-schnitt img {
  display: block; width: 100%; aspect-ratio: 3 / 2; object-fit: cover; background: var(--line);
}
/* Das Kreuz sitzt auf dem Punkt, den es meint - deshalb um seine halbe Groesse
   zurueckgeschoben. Weiss mit schwarzem Rand, damit es auf jedem Foto steht. */
.ed-schnitt-kreuz {
  position: absolute; width: 1.1rem; height: 1.1rem; margin: -.55rem 0 0 -.55rem;
  border: 2px solid var(--paper); outline: 1px solid var(--strong);
  border-radius: 50%; pointer-events: none;
}
.ed-schnitt-satz { margin: .4rem 0 0; }
.ed-bildschau .pruef-von { margin: .4rem 0 0; }


/* ===========================================================================
   DIE VORTEILE - die Zeile, die Vorschau   (07.09.2026)
   ===========================================================================

   Die Zieharmonika ist die der Bildzeile (`.ed-zeile*`); hier steht nur, was
   ein Vorteil anders hat als ein Bild: kein Foto, dafuer ein Satz, eine
   Nebenzeile und **ein Zustandswort**, das sagt, ob der Satz gerade draussen
   steht. Das war die Auskunft, die ganz gefehlt hat: Fuenf Zustaende sind aus
   `active` und zwei Daten rechenbar, und keiner davon stand irgendwo.
   =========================================================================== */

/* Der Satz ist die Sache - wie der Nachweis in der Bildzeile: fett, in
   Textfarbe, und er bricht um statt zu kuerzen. Ein Wort ohne Leerzeichen
   sprengt die Spalte sonst. */
.ed-vorteilsatz { font-size: .95rem; font-weight: 700; color: var(--ink); overflow-wrap: anywhere; }
/* Eine Zeile, die es noch nicht gibt, traegt keinen Namen - also auch nicht
   das Gewicht eines Namens. */
.ed-vorteilsatz-neu { font-weight: 400; color: var(--soft); }
/* Bedingung · Code · Frist - klein, leise, und **nur was da ist**. Auf dem
   Telefon bricht sie um statt zu kuerzen: dieselbe Entscheidung wie beim
   Bildnachweis, aus demselben Grund - was hinten abgeschnitten wird, ist hier
   die Frist. */
.ed-vorteilunten {
  font-size: .8rem; color: var(--soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 45.99rem) {
  .ed-vorteilunten { white-space: normal; overflow: visible; }
}
/**
 * **DER SCHALTER EINER VORTEILSZEILE** (07.09.2026) - Play oder Pause.
 *
 * Er steht an derselben Stelle und in demselben Mass wie der Primärbildstern in
 * der Bildzeile: 2,8 rem, also eine Trefferflaeche fuer einen Daumen, neben
 * dem Aufklapper und nicht darin.
 *
 * **Zwei Formen, dann Farbe.** Play und Pause unterscheiden sich als Zeichen;
 * gruen und grau kommen dazu. Wer die beiden Farben nicht auseinanderhaelt,
 * sieht immer noch ein Dreieck oder zwei Balken - und liest im `aria-label`,
 * was gilt und was der Klick tut.
 *
 * Gefuellt, nicht als Umriss (`fill: currentColor`, wie der gewaehlte Stern):
 * Ein Zustand ist eine Flaeche. Das Gruen ist `--state-live-ink`, derselbe Ton,
 * in dem „auf der Seite" als Marke stand - kein neuer Farbwert.
 */
.ed-schalter {
  flex: none; display: grid; place-items: center;
  width: 2.8rem; height: 2.8rem;
  border: 0; background: none; padding: 0; cursor: pointer;
}
/**
 * **Die Farbe liegt in der Flaeche, nicht im Strich.**
 *
 * Zuerst trug das Zeichen selbst `--state-live-ink` - und das ist mit #22421e
 * ein sehr dunkles Gruen: Auf 1 rem gerechnet las es sich als Schwarz, und
 * „gruen" war es nur, wenn man es wusste. Jetzt bekommt der Schalter das
 * **Paar** der Zustandsmarke (`--state-live-bg` hinter `--state-live-ink`),
 * also genau die Flaeche, in der „auf der Seite" als Wort stand - dieselbe
 * Auskunft, dieselben zwei Toene, kein neuer Farbwert. Pausiert nimmt das
 * neutrale Paar (`--shade` / `--soft`).
 *
 * **Die Flaeche sagt den Zustand, das Zeichen die Handlung.** Gruen, solange
 * der Vorteil laeuft, grau, wenn er ruht - und darin das Zeichen fuer den
 * naechsten Klick, also **Pause** am laufenden und **Play** am ruhenden. Ein
 * gruener Kreis mit Pause heisst deshalb „laeuft, klicken haelt an", nicht
 * „angehalten": Der Knopf zeigt, was er tut, wie an jedem Abspielgeraet.
 *
 * **Rund** (07.09.2026, auf Entscheidung) - die **siebte dokumentierte
 * Ausnahme** von `border-radius: 0`. Hier stand kurz ein eckiger Kasten mit
 * der Begruendung „eine Pille ist eine Marke, die man liest, das hier ist ein
 * Knopf". Das Argument dreht sich aber: Play und Pause sind das eine Zeichen,
 * das jeder Mensch aus einem **runden** Knopf kennt - an einem Geraet, an einem
 * Video, an einem Aufnahmeknopf. Ein Quadrat drumherum liest sich als Kachel,
 * und eine Kachel drueckt man nicht.
 *
 * Die Flaeche ist 1,8 rem, die Trefferflaeche 2,8 - dieselbe Trennung wie beim
 * Plus auf der Zeilenlinie: Der Knopf ist groesser als seine Anzeige.
 */
.ed-schalterflaeche {
  display: grid; place-items: center;
  width: 1.8rem; height: 1.8rem;
  border-radius: 50%;
  background: var(--shade); color: var(--soft);
}
.ed-schalterflaeche svg { width: .95rem; height: .95rem; fill: currentColor; }
.ed-schalter-an .ed-schalterflaeche {
  background: var(--state-live-bg); color: var(--state-live-ink);
}
/* Der Rand kommt beim Zeigen dazu, statt die Flaeche umzufaerben - ein
   Zustandston, der beim Ueberfahren wechselt, laese sich als Umschalten. */
.ed-schalter:hover .ed-schalterflaeche { box-shadow: inset 0 0 0 1px var(--strong); }
.ed-schalter:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
.ed-schalter[disabled] { cursor: default; }
.ed-schalter[disabled] .ed-schalterflaeche { opacity: .5; }

/* Der Deckel erklaert sich dort, wo die Handlung fehlt - der Satz oben sagt es
   auch, aber wer den vierten sucht, sucht am Ende der Liste. */
.ed-vorteilvoll { margin: .6rem 0 0; padding-top: .6rem; border-top: 1px solid var(--line); }
/* Die Linie unter der Liste ist ihr Ende - die letzte Zeile braucht dann keinen
   eigenen Strich mehr, sonst stehen zwei uebereinander. */
.ed-listenteil:has(.zeilenlinie) > .ed-zeilenliste > .ed-zeile:last-child {
  border-bottom: 0;
}
/**
 * Der aufgeklappte Teil einer Zeile **ohne Foto** - die Felder laufen durch,
 * mit demselben Abstand wie in einem Abschnitt.
 *
 * **Die 40 rem sind weg** (07.09.2026). Sie sollten die Eingaben in einer
 * Lesespalte halten, deckelten aber den ganzen Teil - und der traegt einen
 * **Grund**: Unter einer 46-rem-Zeile hoerte die graue Flaeche sechs Zentimeter
 * vor deren rechter Kante auf, als waere sie abgeschnitten. Der Zustand „offen"
 * gehoert der ganzen Zeile, nicht drei Vierteln davon. Die Lesespalte macht
 * ohnehin schon der Abschnitt (46 rem), und ein Eingabefeld darf so breit sein
 * wie die Zeile, aus der es kommt.
 */
.ed-zeileform:not(:has(.ed-bildschau)) { gap: 1rem; }

/**
 * **Die Vorschau ist die eigentliche Bestaetigung** - `BFPChrome.perkBox`,
 * dasselbe Stueck, das der Gast am Eintrag liest. Sie steht **oben** und nicht
 * in der offenen Zeile: Beim Gast ist es ein Kasten mit gemeinsamer Kopfzeile
 * und gemeinsamem Fusssatz; drei kleine Kaesten waeren eine Nachbildung, und
 * „Sag beim Ankommen …" stuende dreimal da.
 */
/* **Kein leerer Kasten, sondern der Satz.** „Gerade steht kein Vorteil auf
   deiner Eintragsseite" ist die ehrlichste Auskunft, die die Vorschau geben
   kann - dieselbe Form wie der Gastkasten, nur ohne Zusage: der Balken in
   `--line` statt `--strong`. */
.ed-vorschau-leer {
  margin: 0; padding: 1rem 1.3rem; color: var(--soft);
  background: var(--shade); border-left: 3px solid var(--line);
}

/* Ohne Vertrag: die Zeile ist kein Knopf mehr, nur noch eine Zeile mit einem
   einzigen Weg hinaus. Kein gesperrtes Formular - eine Tuer, die man sieht und
   nicht aufbekommt, aergert mehr, als sie verkauft. */
.ed-zeilenkopf-still {
  display: flex; align-items: center; gap: .8rem; padding: .7rem .2rem;
}
.ed-zeilenkopf-still .ed-zeilewort { flex: 1; min-width: 0; display: grid; gap: .15rem; }
.ed-zeilenkopf-still .konto-status { flex: none; }
.ed-zeilenkopf-still .ed-vorteilweg { flex: none; color: var(--soft); }
@media (max-width: 45.99rem) {
  .ed-zeilenkopf-still { flex-wrap: wrap; }
  .ed-zeilenkopf-still .ed-zeilewort { flex-basis: 100%; }
}

/* ===========================================================================
   DIE SUCHE IN DER HUELLE - das zweite Quadrat oben links   (05.09.2026)
   ===========================================================================

   Sie ist dieselbe Flaeche wie der Weg zurueck (`.backsquare`): schwarz, so
   hoch wie der Navigationsblock an der anderen Kante. Zwei Quadrate, eine Form
   - und damit die Auskunft „das hier sind die beiden Griffe der Huelle".

   **Wer aussen steht, entscheidet die Bedeutung:** Der Pfeil gehoert zu der
   Seite, auf der man ist, die Lupe zum ganzen Guide. Also Pfeil an der Kante,
   Lupe daneben. Verschoben wird sie nicht von Hand, sondern von der Seite
   selbst: `:has()` fragt, ob ein fester Zurueckknopf im Dokument steht, und
   setzt den Abstand. Ein Umschalter im Skript waere dieselbe Angabe an einer
   zweiten Stelle - und die Eintragsseite zeichnet ihren Knopf erst, wenn die
   Daten da sind. */
:root { --ecke-links: 0px; }
html:has(a.backsquare) { --ecke-links: var(--navheight, 3.7rem); }
.suchknopf { position: fixed; top: 0; left: var(--ecke-links); z-index: 21; }
/**
 * **Below 400 px the way back floats at the foot, centred** - where the thumb
 * is on a small phone, and the top-left corner goes to the magnifier. Round
 * and with a shadow, as in the guest folder: a square lying free over the
 * content reads as a cut-off surface, a circle as a button. When the search
 * opens, it drops out at the bottom instead of sliding left - the corner it
 * slid out of is no longer its own.
 */
@media (max-width: 25rem) {
  html:has(a.backsquare) { --ecke-links: 0px; }
  html:not([data-mappe]) a.backsquare {
    top: auto; left: 0; right: 0; margin-inline: auto;
    bottom: calc(1rem + env(safe-area-inset-bottom));
    border-radius: 999px; box-shadow: 0 4px 16px rgb(0 0 0 / .22);
  }
  html:not([data-mappe])[data-suche="auf"] a.backsquare {
    transform: translateY(calc(100% + 2rem));
  }
}
.suchknopf svg { width: calc(1.15 * var(--chrome-rem)); height: calc(1.15 * var(--chrome-rem)); }

/* **The layer is a `<dialog>` over the whole width, from the top.** It shares
   the scaffold of every layer (`.schicht`: header row, X, the content scrolls)
   and differs in the shape: no frame, no fixed width - on a screen as high as
   its content, on a phone the whole screen. The page behind it is the backdrop
   of the dialog, darkened **and blurred**, so the layer stands off from it in
   light and dark alike - with a line under it the white edge on a dark page
   read as a frame. The page cannot scroll while the search is open, so the
   blur is drawn once and not on every scroll. */
.such-layer {
  position: fixed; inset: 0 0 auto 0; margin: 0;
  width: 100%; max-width: none; max-height: 92dvh;
  border: 0; border-bottom: 1px solid var(--strong);
}
/* **A minimum height on a screen**, as high as the resting state: field, the
   four rows of the quick links and the row to the sender under them -
   otherwise the surface jumps between four lines and twenty with every
   keystroke. It is **measured**, not guessed: 27.5 rem is what the resting
   state stands at, and a smaller number would make the layer shrink the moment
   the first answer arrives. */
.such-layer .schicht-inhalt { padding: 0 1.25rem 2rem; min-height: 27.5rem; }
/* **The content stays in the reading column**, left-aligned in a centered
   column - a result row over 1900 px is no row. */
.such-spalte { width: min(48rem, 100%); margin: 0 auto; }
/* **The magnifier disappears while the search is open.** It is the switch for
   it, and a switch next to the open thing is a second sign for the same state -
   the X in the layer covers it. */
html[data-suche="auf"] .suchknopf { display: none; }
/* **While the search is open, the page does not scroll** - only the layer's
   content does, when it has to (`.schicht-inhalt`, `overflow-y: auto`). A
   modal dialog blocks clicks on the page, not the wheel: the page went on
   scrolling under the darkened backdrop, and whoever came back from the
   search stood somewhere else. `scrollbar-gutter: stable` keeps the space of
   a classic scrollbar reserved while it is hidden, so the page does not jump
   sideways when the layer opens; `overscroll-behavior: contain` on the
   content stops the wheel from handing over to the page at the list's end. */
html[data-suche="auf"] { overflow: hidden; scrollbar-gutter: stable; }
.such-layer .schicht-inhalt { overscroll-behavior: contain; }

/* **Opening is two movements, one after the other - and closing plays them
   back.** The square travels to the right, the white surface opening behind
   it as a strip, and turns into the X on the way; then the strip rolls down
   into the layer. Closing rolls the layer up into the strip and sends the
   square back, the strip closing behind it and the X turning into the
   magnifier again. Each half takes .22 s, the "piece of way" of the
   Styleguide (Bewegung); they cannot overlap, because the second begins
   where the first ends - .44 s in all, the one place in the house over the
   table, with this reason.

   **The travelling square is the X of the header row.** The dialog is shown
   at once (`bindSearch auf`), the fixed magnifier hides in the same frame,
   and the X starts where it stood: `--such-start` and `--such-fahrt` are
   measured there. Two signs lie stacked in the X (`.such-zeichen`,
   `grid-area: 1 / 1`) and fade into each other on the way; a magnifier does
   not become an X, so it is not drawn as if it did.

   **The surface is two boxes, each with its own paper and its own clip.**
   The dialog itself is transparent; the header row and the content carry
   the white. First half: the header row opens in width only - its right edge
   on the square's right edge (both interpolate from the same start with the
   same easing, so they stay together), its left edge at the square's start
   (`--ecke-links`) and running to the corner in the same half - on an entry
   page the back button travels out to the left meanwhile (`a.backsquare`
   below the search rules), and the strip's edge follows its right edge, so
   the button is never painted over but seen leaving. **Its height is nobody's
   calculation:** the row is as high as the X in it, and the X is the square.
   A strip cut out of the whole dialog with `calc(100% - var(--navheight))`
   came out half as high on one machine and cut the square in two - a value
   computed from a percentage of the dialog and a length from a custom
   property, and one browser resolved it differently from another. Now
   nothing is computed. Second half: the content rolls down under the row
   (`inset(0 0 100% 0)` to `inset(0)`, pure percentages), and the row's left
   edge goes to the corner. The keyframes carry the easing per half
   (`ease-in-out` applies to each interval), and every part of the movement -
   row, content, square, signs, word, backdrop - is a keyframe set of the
   same length with its turn at 50 %, so nothing can drift. Closing plays the
   same animations backwards (`bindSearch zu`, `Animation.reverse()`), and
   `both` holds the first frame until the dialog closes - the stylesheet
   knows only the way there.

   **Results end the movement** (`bindSearch suchen`, `finish()`): the focus
   is in the field from the first frame, so typing starts at once, and an
   answer landing while the surface is still rolling would change its height,
   and with it the roll, in flight.

   The Styleguide's "nothing that changes height" is a rule for content that
   pushes what lies under it. The layer lies over the page and pushes nothing;
   what is revealed is its own surface. */
/* One duration for all parts - they must run in step. For looking at the
   movement, set it ten times slower (4.4s): a screenshot then catches the
   strip and the square on the way. Whoever sets it slow sets it back. */
.such-layer { --such-dauer: .44s; }
/* The paper lies on the two boxes, not on the dialog; the header's line moves
   to the top of the content, so the strip is white to its last pixel and the
   line arrives with the roll. The content grows to the bottom of the dialog -
   on the phone the dialog is the screen, and a transparent dialog would show
   the dark page under a content that ends early. */
.such-layer { background: transparent; border-bottom: 0; }
.such-layer .schicht-kopf { background: var(--paper); border-bottom: 0; }
.such-layer .schicht-inhalt {
  flex-grow: 1; background: var(--paper);
  border-top: 1px solid var(--line); border-bottom: 0;
}
/* The resting state of the backdrop - also where no motion is wanted. */
.such-layer::backdrop { background: rgb(0 0 0 / .55); backdrop-filter: blur(6px); }
.such-layer .schicht-zu { display: grid; place-items: center; }
.such-zeichen { grid-area: 1 / 1; display: inline-flex; }
.such-zeichen-lupe { opacity: 0; }
.such-layer[open] .schicht-kopf { animation: such-streifen var(--such-dauer) ease-in-out both; }
.such-layer[open] .schicht-inhalt { animation: such-rollen var(--such-dauer) ease-in-out both; }
.such-layer[open]::backdrop { animation: such-abdunkeln var(--such-dauer) ease-in-out both; }
.such-layer[open] .schicht-zu { animation: such-fahren var(--such-dauer) ease-in-out both; }
.such-layer[open] .such-zeichen-lupe { animation: such-lupe var(--such-dauer) ease-in-out both; }
.such-layer[open] .such-zeichen-x { animation: such-x var(--such-dauer) ease-in-out both; }
.such-layer[open] .schicht-kopf-wort { animation: such-wort var(--such-dauer) ease-in-out both; }
@keyframes such-streifen {
  from { clip-path: inset(0 calc(100% - var(--such-start, 0px)) 0 var(--ecke-links, 0px)); }
  50%, to { clip-path: inset(0 0 0 0); }
}
@keyframes such-rollen {
  from, 50% { clip-path: inset(0 0 100% 0); }
  to { clip-path: inset(0 0 0 0); }
}
@keyframes such-fahren {
  from { transform: translateX(calc(-1 * var(--such-fahrt, 0px))); }
  50%, to { transform: translateX(0); }
}
@keyframes such-lupe { from { opacity: 1; } 50%, to { opacity: 0; } }
@keyframes such-x { from { opacity: 0; } 50%, to { opacity: 1; } }
@keyframes such-wort { from, 50% { opacity: 0; } to { opacity: 1; } }
/* **The page darkens first, in the first 66 ms** - not across the whole trip.
   The strip is white, and while the page behind it is still bright (a sky in
   the picture) white on bright is no surface but a line; it read as thinner
   on the way out than on the way back, where the page was already dark. Now
   the ground is there before the strip has moved a hand's width. Played
   backwards, the page brightens in the last 66 ms, when the square is nearly
   home. */
@keyframes such-abdunkeln {
  from { background: rgb(0 0 0 / 0); backdrop-filter: blur(0); }
  15%, to { background: rgb(0 0 0 / .55); backdrop-filter: blur(6px); }
}
@media (prefers-reduced-motion: reduce) {
  .such-layer[open] .schicht-kopf,
  .such-layer[open] .schicht-inhalt,
  .such-layer[open]::backdrop,
  .such-layer[open] .schicht-zu,
  .such-layer[open] .such-zeichen,
  .such-layer[open] .schicht-kopf-wort { animation: none; }
}

/* **The round slot** (`.suchschlitz`) - the one shape everybody knows a search
   box by, and the documented exception from `border-radius: 0` (Styleguide,
   exception list); it holds for this one component. Magnifier left as a sign,
   the field, no button right. A line draws the edge, no shadow: the slot lies
   on quiet paper, and a shadow would be a height that is not there. Grey at
   rest, black active - the same language as every field of the guide; the
   frame changes colour, not thickness. The focus lies on the slot, not inside
   it: a ring inside would run along the round edge like a second slot. */
.suchschlitz {
  display: flex; align-items: center; gap: .7rem;
  margin: 1.6rem 0 1.4rem; padding: 0 1.4rem 0 1.2rem;
  border: 1px solid var(--line); border-radius: 999px; background: var(--paper);
}
.suchschlitz:focus-within { border-color: var(--strong); }
.suchschlitz input[type=search] {
  flex: 1; min-width: 0; border: 0; background: none; color: var(--ink);
  font: inherit; font-size: 1.05rem; padding: 1rem 0;
}
.suchschlitz input[type=search]:focus-visible { outline: none; }
.suchschlitz input::placeholder { color: var(--soft); opacity: 1; }
.such-lupe { display: inline-flex; flex: none; color: var(--soft); }
.such-lupe .nav-icon { width: 1.25rem; height: 1.25rem; }


/* **The quick links** - a small heading in the quiet tone, under it the six
   ways: each its mark in a filled circle and its word. No frame, no ground:
   they are a list of ways, not a menu. Hidden as soon as results stand there.

   **Three forms, chosen by the width of the layer, not of the window**
   (`container-type` on the nav): the search column is at most 48 rem wide,
   and what matters is the room the ways have.

   | Width | Form |
   |---|---|
   | under 34 rem (phone) | one column, circle left, word right, 44 px per row |
   | 34 to 44 rem | two columns - left the four categories, right calendar and magazine |
   | from 44 rem (screen) | three columns of two rows, each row the phone row: circle left, word right |

   **The split stays in every form:** what the guide lists, then what lies
   across it (a date, a story). On the screen the third column is that second
   group - the fifth way (`.quick-quer`) opens it explicitly, so a missing
   category leaves a gap in the first two columns instead of pulling the
   calendar over. Space only; a vertical line between the columns reads as
   the divider of a toolbar. */
.quick-links { container: quick / inline-size; }
.quick-links-titel { margin: 0 0 .5rem; color: var(--soft); font-size: .85rem; }
.quick-links ul { list-style: none; margin: 0; padding: 0; }
@container quick (min-width: 34rem) {
  .quick-links ul {
    display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: repeat(4, auto);
    grid-auto-flow: column; column-gap: 2rem;
  }
}
@container quick (min-width: 44rem) {
  .quick-links ul {
    grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-rows: repeat(2, auto);
    grid-auto-flow: column; column-gap: 2rem;
  }
  .quick-links ul li.quick-quer { grid-column: 3; grid-row: 1; }
}

/* **One way: circle and word** - and `ul a`, not `a`: under the list stands a
   second link in the same `<nav>` (the row to the sender), and it is not a row
   of this list. */
.quick-links ul a.quick-weg {
  display: flex; align-items: center; gap: .75rem;
  min-height: 44px; padding: .3rem 0; color: var(--ink); text-decoration: none;
}
.quick-links ul a.quick-weg:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }

/* **Circle, sign and word carry the category colour** - the circle drawn like
   a pin on the interactive map: at rest a ring and the sign in the category
   colour on paper, under the pointer and in focus the full surface with the
   sign white on it. The outline keeps six coloured marks quiet in a layer
   that is about the search field; the fill answers the pointer.

   Round is documented exception 12 ("the mark in a circle"). The colour reads
   the same contract as `.rubrikfeld`: `--rf-voll` is the category colour,
   gold through its ink (5.6 : 1 on paper); on the full surface the sign is
   white (`--auf-bild-ink`), on the field without a category colour (events,
   `--strong`) it takes `--paper`, so it turns with the mode.

   **The ring draws the weight of the sign**, as on the map: 1 px (sign
   0.83 px) - one size in every form. The word takes the same
   colour as ring and sign (`--quick-linie`, on the link): 5.6 to 12.7 : 1 on
   paper. In dark mode all three are mixed half with `--strong` (6.3 to
   8.6 : 1) - pure, Entdecken measures 2.1 : 1 on the
   dark paper; the full surface stays pure. */
.quick-kreis {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 2.25rem; height: 2.25rem; border-radius: 999px;
  border: 1px solid var(--quick-linie); color: var(--quick-linie); background: var(--paper);
  transition: background-color .15s, color .15s, border-color .15s;
}
.quick-weg { --quick-linie: var(--rf-voll); }
:root[data-theme="dark"] .quick-weg { --quick-linie: color-mix(in srgb, var(--rf-voll) 50%, var(--strong)); }
.quick-links ul a.quick-weg .quick-wort { color: var(--quick-linie); }
.quick-weg:hover .quick-kreis,
.quick-weg:focus-visible .quick-kreis {
  background: var(--rf-voll); border-color: var(--rf-voll); color: var(--rf-auf, var(--auf-bild-ink));
}
.quick-weg[data-ton="strong"] { --rf-auf: var(--paper); }
.quick-kreis .quick-icon { width: 1.25rem; height: 1.25rem; }
@media (prefers-reduced-motion: reduce) { .quick-kreis { transition: none; } }

/* **The row to the sender** - portrait left, name and one sentence right.

   **Not a seventh quick link.** The six ways are meant to be equally loud;
   a row with a face in it is three times as high and wins every look - and a
   portrait would then stand over "Übernachten". So it lies under the list,
   parted by one hairline, quieter than what stands above it - but inside the
   same `<nav>`, so the existing switch takes it along when results come.

   Two columns like a suggestion, and the same size as the square in front of
   one (`--such-thumb`, 44 px) - but **round**, like every portrait in this
   house (`.nav-konto-bild`, `.avatar-schau`, the profile picture). That is
   documented exception 2 of `border-radius: 0` and reads the same way here: a
   portrait in a circle is a round shape, not a round box.

   **No heading, two lines and a way in.** The sentence says what this is and
   carries "Mehr erfahren" right behind it, in the same flow and the same size -
   a heading would have named the place without giving a reason to go there.
   The sentence is quiet (`--soft`), the way inside it is black and underlined:
   in a row that is a link as a whole, the underlined part is what you aim at.
   The block is centred against the portrait, so the face sits beside the
   sentence and not above it. Nothing moves under the pointer - the underline is
   already there, and it thickens. */
.quick-about {
  display: grid; grid-template-columns: var(--such-thumb) minmax(0, 1fr);
  gap: 0 .7rem; align-items: center;
  margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--line);
  color: inherit; text-decoration: none;
}
.quick-about .such-bild { border-radius: 50%; }
.quick-about-satz { color: var(--soft); font-size: .88rem; }
.quick-about-mehr {
  color: var(--strong); text-decoration: underline; text-underline-offset: .2em;
}
.quick-about:hover .quick-about-mehr,
.quick-about:focus-visible .quick-about-mehr { text-decoration-thickness: 2px; }
.quick-about:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }


/* The sentence above the list: the number, the hint or the error. Information,
   not a heading - small and muted. And it is only there when it says something:
   `:empty` takes its spacing away with the box. */
.such-satz { margin: .2rem 0 1rem; color: var(--soft); font-size: .9rem; }
.such-satz:empty { display: none; }
.such-treffer { list-style: none; margin: 0 0 1.4rem; padding: 0; }
.such-treffer:empty { margin: 0; }
/* Inset left and right: the grey of the hovered row reaches the hairlines, the
   text keeps its distance from the edge of that grey - the same .7rem as the
   gap between picture and name. */
.such-treffer a {
  display: block; padding: .7rem; border-top: 1px solid var(--line);
  text-decoration: none; color: inherit;
}
.such-treffer li:last-child a { border-bottom: 1px solid var(--line); }
.such-treffer a:hover, .such-treffer a:focus-visible { background: var(--shade); }
.such-treffer a:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
.such-name { display: block; font-weight: 700; }
.such-ort { display: block; color: var(--soft); font-size: .88rem; }

/**
 * **The square in front of a suggestion.** The grid exists only with a picture
 * (`:has(.such-bild)`): without one `suchBild` draws nothing, and a row with
 * two children in a two-column grid put the place under the square instead of
 * next to the name. Without the grid the row is what it always was: two lines
 * at the left edge.
 *
 * Two columns, two rows: picture left over both rows, name and place right.
 * The second column is `minmax(0, 1fr)`, otherwise a long name pushes the
 * picture out of the row. The square is `--such-thumb` (44 px), the size of the
 * picture in the backend tables - not the 60 px of the lists.
 *
 * **The square says its size, the row says its place.** Where the picture sits
 * in the grid belongs to the row that builds the grid, not to the picture -
 * `.quick-about` under the quick links uses the same square in a grid of its
 * own, and a `grid-column` carried along would be an instruction from a row it
 * does not stand in.
 */
.such-treffer a:has(.such-bild) {
  display: grid; grid-template-columns: var(--such-thumb) minmax(0, 1fr);
  gap: 0 .7rem; align-items: center;
}
.such-treffer a:has(.such-bild) .such-bild { grid-column: 1; grid-row: 1 / span 2; align-self: center; }
.such-treffer .such-bild, .quick-about .such-bild { width: var(--such-thumb); height: var(--such-thumb); }
.such-bild {
  width: var(--thumb); height: var(--thumb); border-radius: var(--thumb-radius);
  object-fit: cover; display: block; background: var(--shade);
}
.such-name, .such-ort { grid-column: 2; }
.such-alle { margin: 0 0 1.4rem; font-size: .9rem; color: var(--soft); }
.such-alle[hidden] { display: none; }

/* **On a phone the layer is the screen.** Full height, no bottom edge; the field
   a little smaller, the list closer to it - the first result should be visible
   without swiping. */
@media (max-width: 34rem) {
  .such-layer { height: 100dvh; max-height: 100dvh; border-bottom: 0; }
  .such-layer .schicht-inhalt { padding: 0 1rem 1.5rem; min-height: 0; }
  .suchschlitz { margin: 1.2rem 0 .8rem; }
  .such-satz { margin: .1rem 0 .5rem; }
}

/* Wonach gesucht wurde - im Editor unter den Stichworten, im Backend als
   eigene Flaeche.

   Die Woerter sind **Knoepfe**, keine Marken: Ein Klick setzt eines zu den
   Stichworten dazu. Deshalb tragen sie einen Rahmen und keinen gefuellten
   Grund - gefuellt sieht aus wie „ist gesetzt", und gesetzt ist hier nichts,
   bevor jemand gespeichert hat.

   **Und sie sind Pillen** (07.09.2026) - dieselbe Form wie die Gattungen unter
   der Suche (`.gattungs-pillen a`): Rahmen in `--line`, `999px`, `.35rem .8rem`.
   Das ist keine neue Ausnahme von der eckigen Marke, sondern die vorhandene
   Hausform fuer **eine Reihe kurzer Woerter zum Antippen** - und genau das
   steht hier. Eckig standen sie als kleine Kaesten zwischen lauter eckigen
   Eingabefeldern und lasen sich wie ein weiteres Formularstueck; rund sind sie
   erkennbar etwas anderes als das Feld darueber, in das sie hineingehen. */
.ed-gesucht-liste {
  list-style: none; margin: .6rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: .4rem;
}
.ed-wort {
  display: inline-flex; align-items: baseline; gap: .4rem;
  border: 1px solid var(--line); border-radius: 999px;
  background: none; color: inherit; white-space: nowrap;
  font: inherit; font-size: .88rem; padding: .35rem .8rem; cursor: pointer;
}
.ed-wort small { color: var(--soft); }
.ed-wort:hover { border-color: var(--strong); background: var(--shade); }
.ed-wort:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }

/* Der Zeitraum ueber der Suchliste: Beschriftung und Auswahl in einer Zeile. */
.such-zeitraum { display: flex; align-items: center; gap: .6rem; margin: 1.4rem 0 .8rem; }
.such-zeitraum label { color: var(--soft); font-size: .9rem; }

/* ===========================================================================
   DER REITER „FAQ" - die Zeile einer Frage   (07.09.2026)
   ===========================================================================

   Fast nichts Eigenes: Die Zeile ist `.ed-zeile*` in ihrer Grundform (Pfeil,
   Wort, Mangel) - dieselbe, die die Vorteile tragen. Was hier steht, ist der
   Text darin, und er folgt derselben Rangfolge wie in der Bildzeile: die
   Sache fett und in Textfarbe, die Beigabe klein und leise.
   =========================================================================== */

/* Die Frage ist die Sache. Sie **bricht um** statt zu kuerzen - „Welche
   Schwarzwälder Spezialität …" ist keine Frage mehr, und ein Fragezeichen, das
   fehlt, aendert den Satz. Zwei Zeilen genuegen fuer die laengste im Katalog. */
.ed-faqfrage {
  font-size: .95rem; font-weight: 700; color: var(--ink); overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* Eine Frage, die es noch nicht gibt, traegt kein Gewicht - wie „Neuer Vorteil". */
.ed-faqfrage-neu { font-weight: 400; color: var(--soft); }
/* Der Vorrat ist leiser als das Ergebnis: Diese Zeilen sind die Aufgabe, nicht
   der Inhalt. Fett bleiben sie trotzdem nicht - sonst waeren 12 unbeantwortete
   Fragen lauter als 7 beantwortete. */
.ed-faqfrage-offen { font-weight: 400; }
/* Der Anfang der Antwort, eine Zeile. Auf dem Telefon faellt sie weg statt
   umzubrechen: Dort ist die Frage die Auskunft, die Vorschau ist die Zugabe. */
.ed-faqvor {
  font-size: .8rem; color: var(--soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 45.99rem) {
  .ed-faqvor { display: none; }
}
/* Zwei Gruppen in einer Liste: „Beantwortet" und „Noch keine Antwort". Die
   Ueberschrift traegt die Zahl - damit ist „ist noch was offen?" ohne Zaehlen
   zu beantworten. */
.ed-faqgruppe {
  font-size: .85rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--soft); margin: 1.4rem 0 .2rem;
}
/* Der Vorrat ist erledigt - eine Zeile, keine Warnfarbe: Das ist das Ziel und
   kein Zustand, den jemand beheben muss. */
.ed-faqfertig { margin-top: 1rem; }
/**
 * **„Weitere Fragen aus dem Katalog"** (07.09.2026) - der Rest des Katalogs,
 * zu, bis jemand ihn braucht. Im Vorrat darueber stehen nur die wesentlichen:
 * an einem Campingplatz passten 19 Fragen, und eine Arbeitsliste, die den
 * Bildschirm fuellt, ist keine.
 *
 * **Warum ueberhaupt erreichbar, wenn es „Neue Frage" gibt?** Eine Katalogfrage
 * bringt ihre drei Sprachen mit (`questionTemplates.texts`); eine frei
 * getippte braucht fuenf eigene Uebersetzungen. Der Aufklapper ist damit kein
 * Komfort, sondern der billigere Weg.
 */
.ed-faqmehr { margin-top: 1.2rem; }
.ed-faqmehr .ed-zeilenliste { margin-top: .2rem; }
/**
 * **Der Aufklapper ist eine dritte Gruppenueberschrift, keine Zeile.**
 *
 * `.ed-aufklapp > summary` ist halbfett in `--ink` gebaut - richtig fuer eine
 * Erklaerung, die zwischen Feldern steht. Hier stand damit das **dunkelste und
 * fetteste** Wort des ganzen Vorrats unter zwei leisen Versalzeilen: Die
 * unwichtigere Liste hatte die lautere Marke. Jetzt stehen drei gleichartige
 * Marken untereinander („BEANTWORTET (3)", „NOCH KEINE ANTWORT (6)", „WEITERE
 * FRAGEN AUS DEM KATALOG (30)") und darunter **eine** Handlung - und
 * Aufklapper und Linie hoeren auf, um dieselbe Aufmerksamkeit zu ringen, weil
 * sie nicht mehr dieselbe Sorte Ding sind.
 */
.ed-faqmehr > summary {
  font-size: .85rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--soft);
}
/**
 * **Diese Linie traegt ihr Wort** - anders als die der Zeitenspannen und der
 * Merkmale, wo das Plus beim Zeigen erscheint und sonst nichts steht.
 *
 * Der Grund ist, was **darueber** steht: Bei den Zeiten ist es die letzte Zeile
 * derselben Sorte, die den Knopf erklaert („noch eine Spanne"). Hier stehen
 * darueber **fremde** Fragen aus dem Katalog - eine stumme Linie darunter liest
 * sich als „noch eine davon", und dass man hier eine **eigene** Frage stellt,
 * findet niemand durch Hinfahren. Es war die erste Frage nach dem Umbau.
 *
 * Deshalb: Zeichen und Wort, immer sichtbar, und beide **unter** der Linie
 * statt auf ihr - auf der Linie waere das Wort ein Aufkleber, der die Liste
 * darueber zerschneidet.
 */
.zeilenlinie.ed-faqneu {
  /* **`min-height`, nicht `height`.** Zwei Klassen schlagen die eine in
     `@media (hover: none) { .zeilenlinie { height: 2.75rem } }` - Mediaabfragen
     zaehlen bei der Spezifitaet nicht. Mit `height: auto` war die Linie auf dem
     Telefon 34 px hoch: genau die Regel, wegen der die stumme Linie am
     06.09.2026 auf 2,75 rem gegangen ist. `min-height` laesst sie zugleich
     wachsen, wenn das Wort umbricht. */
  height: auto; min-height: 2.75rem;
  padding: .55rem 0 .15rem;
  /* **Abstand statt Abschlusskante.** Diese Linie heisst ausdruecklich nicht
     „noch eine davon", also spielt sie auch nicht das Ende der Liste - die
     letzte Zeile gibt dafuer ihren eigenen Strich ab (Regel unten), sonst
     staenden hier zwei Haarlinien mit 14 px Nichts dazwischen. */
  margin-top: .9rem;
  display: flex; align-items: center; justify-content: center; gap: .45rem;
  color: var(--soft);
}
.ed-faq .ed-zeilenliste:has(+ .zeilenlinie) > .ed-zeile:last-child {
  border-bottom: 0;
}
/* Die neue Zeile steht an der Stelle des Knopfes - also mit seinem Abstand.
   Sie ist eine Liste fuer sich: Was noch keine Antwort hat, gehoert nicht unter
   die Ueberschrift „Beantwortet". */
.ed-faqneuzeile { margin-top: .9rem; }
.zeilenlinie.ed-faqneu .linieplus {
  position: static; transform: none; opacity: 1;
}
/* Das Wort ist ein Knopfwort, keine Nebenauskunft - `--soft` auf `--paper`
   steht mit 4,47 : 1 knapp unter der AA-Grenze fuer 14,4 px. */
.ed-liniewort { font-size: .9rem; font-weight: 600; color: var(--ink); }
.zeilenlinie.ed-faqneu:hover, .zeilenlinie.ed-faqneu:focus-visible {
  color: var(--strong);
}
.zeilenlinie.ed-faqneu:hover .ed-liniewort,
.zeilenlinie.ed-faqneu:focus-visible .ed-liniewort { color: var(--strong); }
/**
 * **Und dieser Knopf bekommt seinen Ring zurueck.** `.zeilenlinie:focus-visible
 * { outline: none }` gilt der stummen Linie: Dort blendet der Plus-Ring von 0
 * auf 1 ein, das **ist** die Fokusanzeige. Hier blendet nichts ein, die Form
 * aendert sich nicht - uebrig bliebe allein ein Farbwechsel. Der Knopf hat mit
 * Zeichen und Wort ohnehin einen Kasten, anders als die nackte Linie, wo ein
 * Ring ein Rechteck erfunden haette. Derselbe Ring wie an `.ed-aufklapp > summary`
 * zwei Zentimeter darueber.
 */
.zeilenlinie.ed-faqneu:focus-visible {
  outline: 2px solid var(--strong); outline-offset: 2px;
}
/* „Geprüft am" und der Knopf „Heute" nebeneinander - dieselbe Mechanik wie der
   Pin und „Gemeinde aus der Koordinate": Ein Werkzeug fuellt ein Feld, ein
   Mensch drueckt den Knopf. */
/* Der Abschnitt bleibt in der Lesespalte. **Anders als Bilder und Zeiten**, die
   auf 58 rem gehen: Dort war der Grund ein Raster bzw. ein Vorschaubild - hier
   steht nur Text, und Text liest man nicht ueber 46 rem. */
.ed-faq { max-width: 46rem; }

/* **Die Mangelspalte ist hier breiter als bei einem Bild** - dort stehen kurze
   Worte („ohne Urheber"), hier stehen laengere („ohne Prüfdatum"), und ohne
   Vorschaubild ist der Platz da. Mit den 8 rem der Grundform brach „offen ·
   ohne Quelle · ohne Prüfdatum" aus der Spalte heraus und stand halb unter dem
   Fragetext. Rechtsbuendig, damit die Kante steht, wenn eine Zeile umbricht. */
@media (min-width: 46rem) {
  .ed-faq .ed-zeileauf { grid-template-columns: 1.2rem minmax(0, 1fr) 13rem; }
  .ed-faq .ed-zeileauf:not(:has(.ed-zeilemangel)) {
    grid-template-columns: 1.2rem minmax(0, 1fr);
  }
  .ed-faq .ed-zeilemangel { justify-content: flex-end; }
}
/* Eine verworfene Zeile ist leiser - wie ein abgelehntes Bild in seiner
   Kachel. Hier gibt es kein Bild, gedimmt wird deshalb der Text. Nicht die
   ganze Zeile: Das Zustandswort „verworfen" ist der Grund, warum sie leise
   ist, und muss lesbar bleiben. */
.ed-faq .ed-zeile[data-status="rejected"] .ed-zeilewort { opacity: .55; }

/* ===========================================================================
   DIE WETTERSEITE - zwoelf Messpunkte, eine Aussage
   ===========================================================================

   `/schwarzwald-wetter/` (10.09.2026), gezeichnet von `web/wetter.js`, gefuellt
   von `web/wetter-werte.js`.

   **Der Text bleibt in der Lesespalte, Karte und Tabelle greifen darueber
   hinaus** - dieselbe Bauart und dieselbe Begruendung wie bei der Galerie auf
   `/merchandise/`: Ein Bild ist keine Zeile, und eine Tabelle mit vier Spalten
   auch nicht. Absaetze ueber 100 Zeichen liest niemand gern; eine Karte, die
   auf Textbreite gedeckelt ist, zeigt den Schwarzwald als Briefmarke.

   Und dieselbe Grenze: `1000rem` ist keine Breite, sondern das abgeschaffte
   Mass - was wirklich begrenzt, ist `min(var(--rahmen), …)` darunter.

   **Das geht nur ohne Abschnittsverzeichnis, und deshalb hat die Seite
   keins.** `abschnittsnav` macht aus dem Artikel ein zweispaltiges Raster
   (`.about-mitnav`): links 17 rem Verzeichnis, rechts die Lesespalte. Der
   Block rechnet seinen negativen Rand gegen die **Spalte** und schoebe sich
   damit in das Verzeichnis hinein - eine Flaeche, die eine Navigation
   ueberdeckt, nimmt nicht Platz, sondern Bedienbarkeit. Die Entscheidung
   steht in `web/wetter.js`: Diese Seite hat einen Mittelpunkt, kein
   Inhaltsverzeichnis. */
.wetterpage { --galerie: 1000rem; }
.wetter-jetzt {
  --rahmen: calc(min(100vw, var(--rahmen-breite)) - 2 * var(--inset));
  --breite: min(var(--rahmen), var(--galerie, 57rem));
  width: var(--breite);
  margin-left: calc((100% - var(--breite)) / 2);
}
/* Die Ueberschrift und die Quellzeile gehoeren zum Text und bleiben schmal -
   sonst stuende ein Satz von 1060 px unter einer Tabelle, die ihn braucht. */
.wetter-jetzt > h2,
p.wetter-quelle { max-width: var(--text); margin-inline: auto; }

/**
 * **Die Karte hat ihre Hoehe, bevor sie da ist.**
 *
 * Sie kommt aus einer Insel, also erst nach dem ersten Anstrich. Ohne
 * `aspect-ratio` waere der Platz null und die halbe Seite spraenge nach unten,
 * sobald MapLibre fertig ist - derselbe Sprung, den der Themenblock im Fuss
 * einmal gekostet hat (CLS 0.145).
 *
 * 16:9 am Schirm, hochkant auf dem Telefon: Der Schwarzwald ist lang und
 * schmal, und in einem breiten Streifen auf 390 px waere er ein Faden.
 */
.wetter-karte {
  aspect-ratio: 3 / 4; width: 100%; max-width: 100%;
  border: 1px solid var(--line); background: var(--shade);
  margin: 0 0 1.5rem;
}
@media (min-width: 40rem) {
  .wetter-karte { aspect-ratio: 16 / 9; }
}

/**
 * **Die Pille sagt die Zahl, darunter steht, wo.**
 *
 * Auf `--paper` mit einem Rahmen, damit sie auf jeder Kachelfarbe traegt -
 * eine Zahl direkt auf der Karte verschwindet ueber einem Wald. Der Ortsname
 * ist leiser: Man sucht die Zahl und liest den Namen erst, wenn eine auffaellt.
 *
 * **Rund - eine der dokumentierten Ausnahmen** von `border-radius: 0`.
 *
 * Sie gilt aus demselben Grund wie bei der Zustandsmarke
 * (`.konto-status`): **Die Form sagt, dass man das hier nicht anklickt.** Eine
 * Marke auf einer Karte ist eine Auskunft, kein Bedienelement - sie traegt
 * `pointer-events: none`, und eckig saehe sie aus wie einer der Knoepfe, die
 * oben rechts in derselben Karte stehen.
 *
 * Die Innenabstaende wachsen mit: In einer Pille sitzt die Zahl sonst an der
 * Rundung.
 */
.wetterpille {
  display: flex; flex-direction: column; align-items: center; gap: .1rem;
  line-height: 1.1; pointer-events: none; user-select: none;
}
.wetterpille-wert {
  display: inline-flex; align-items: center; gap: .25rem;
  padding: .15rem .6rem;
  border-radius: 999px;
  background: var(--paper); border: 1px solid var(--strong);
  color: var(--strong); font-weight: 600; font-size: .9rem;
  font-variant-numeric: tabular-nums;
}
.wetterpille-icon { width: .95rem; height: .95rem; flex: none; }
.wetterpille-ort {
  font-size: .7rem; color: var(--ink);
  /* Der Name liegt auf der Karte, nicht auf Papier - ein schmaler heller Saum
     haelt ihn ueber jedem Untergrund lesbar, ohne einen zweiten Kasten. */
  text-shadow: 0 0 3px var(--paper), 0 0 3px var(--paper);
}

/**
 * **Die Tabelle rollt, die Seite nicht** - die Hausregel fuer Tabellen. Vier
 * Spalten passen auf 390 px, aber knapp; wer eine laengere Wetterlage bekommt
 * ("Teils bewölkt"), schiebt sonst die ganze Seite zur Seite.
 */
.wetter-tabelle { overflow-x: auto; }
.wetter-tabelle table {
  width: 100%; border-collapse: collapse; font-size: .95rem;
}
.wetter-tabelle th, .wetter-tabelle td {
  text-align: left; padding: .5rem .6rem;
  border-bottom: 1px solid var(--line);
}
.wetter-tabelle thead th {
  font-size: .78rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--soft); font-weight: 600; white-space: nowrap;
}
.wetter-tabelle tbody th { font-weight: 600; color: var(--strong); }
/* Hoehe und Grad sind Zahlen: rechtsbuendig und mit gleich breiten Ziffern,
   damit die Spalte eine Kante hat und man die Reihenfolge sieht. */
.wetter-tabelle .wetter-hoehe,
.wetter-tabelle .wetter-grad,
.wetter-tabelle .wetter-spalte-grad {
  text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.wetter-tabelle .wetter-hoehe { color: var(--soft); }
.wetter-tabelle .wetter-grad { font-weight: 600; color: var(--strong); }
.wetter-tabelle .wetter-lage { color: var(--ink); }

/* Die Quellzeile ist eine Fussnote, keine Zeile des Textes: Die Nennung des
   DWD ist Pflicht (offene Daten), der Stand daneben eine Auskunft ueber die
   Zahlen darueber - beides gehoert leise unter die Tabelle und nicht in ihre
   Groesse.

   **`.68rem` ist der Boden des Hauses**, nicht eine hier erfundene Zahl: Es
   ist die kleinste Groesse, die im Stylesheet vorkommt (Kalenderwochentag,
   Zaehlerpille). Tiefer geht es nicht - `--soft` auf `--paper` steht hell bei
   4,7 : 1, also knapp ueber AA, und das gilt fuer die Farbe, nicht fuer eine
   beliebige Groesse darunter.

   **Der Elementname steht im Selektor, und das ist Absicht.** Die Zeile ist
   ein `p` in einem `.about-block`, und der setzt seinen Absaetzen 1,02rem mit
   Klasse *und* Element - ein blosses `.wetter-quelle` verliert dagegen, und
   zwar lautlos: Farbe und Breite kommen an, Groesse, Rand und Mittigkeit
   nicht. Die Zeile stuende dann in Vorlesegroesse links unter einer Tabelle,
   die sie nur begleitet. */
p.wetter-quelle {
  margin: .9rem 0 0; font-size: .68rem; color: var(--soft);
  display: flex; flex-wrap: wrap; gap: .35rem .6rem;
}
.wetter-fehler { color: var(--ink); }

/**
 * **The subscription page** - three cards side by side, Member first, then
 * the two plans (one below the other on a phone), the current tier framed.
 * 13 rem so three fit next to each other in the reading column. The price is the one number
 * on the card and stands large; a discount strikes the old price through.
 */
.abo-plaene { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: 1rem; margin: 0 0 1.4rem; }
/* **The three plans: one column, or all three - never two.** Two beside one
   read as a pair and a leftover, and the tier that stands alone looks like a
   different kind of thing. Asked of the page's own width, not the window's:
   the navigation column beside it takes a share that changes. 41 rem is three
   cards of 13 rem and their two gaps. */
#abo-tafel { container-type: inline-size; }
.abo-plaene:not(.abo-einmalig) { grid-template-columns: 1fr; }
@container (min-width: 41rem) {
  .abo-plaene:not(.abo-einmalig) { grid-template-columns: repeat(3, 1fr); }
}
.abo-plan {
  display: flex; flex-direction: column; gap: .5rem;
  border: 1px solid var(--line); border-radius: var(--card-radius, 6px); padding: 1.1rem 1.2rem;
  background: var(--paper);
}
.abo-plan.ist-gebucht { border-color: var(--strong); box-shadow: inset 0 0 0 1px var(--strong); }
.abo-plan h2 { margin: 0; font-size: 1.15rem; }
/* The card's name is the tier pill - the same mark as in the account menu,
   a size larger because here it is the heading. */
.abo-plan-kopf { line-height: 1; }
.abo-plan-kopf .plan-pille { margin-left: 0; vertical-align: 0; font-size: .8rem; padding: .25rem .7rem; }
.abo-plan ul { margin: .2rem 0 .6rem; padding-left: 1.1rem; font-size: .92rem; }
.abo-plan li { margin: 0 0 .25rem; }
.abo-plan .action { margin-top: auto; align-self: flex-start; }
.abo-preis { margin: 0; font-size: .95rem; color: var(--soft); }
.abo-preis strong { font-size: 1.5rem; color: var(--strong); font-variant-numeric: tabular-nums; }
.abo-preis s { margin-right: .3rem; }
.abo-code-satz { margin: 0; font-size: .85rem; color: var(--state-live-ink, var(--soft)); }
.abo-gebucht { margin-top: auto; font-weight: 600; }
/* The running tier: a pill in the state pair for "live", tick in front. */
.abo-aktiv {
  align-self: flex-start; display: inline-flex; align-items: center; gap: .35rem;
  padding: .3rem .75rem .3rem .55rem; border-radius: 999px;
  background: var(--state-live-bg); color: var(--state-live-ink);
}
.abo-aktiv svg { width: 1rem; height: 1rem; fill: none; stroke: currentColor; stroke-width: 2; }
/* **The plans on a ground, the Zusatzleistungen on paper.** Both are cards;
   the plans - the products one chooses between - stand on a quiet ground and
   carry the weight, the offers bought once stay white with a hairline. The
   ground is `--shade`, the quiet fill of the house. **The hairline stays on
   it**: in dark `--shade` is the card ground itself (`#1b2126`), and without
   an edge the plans would stand invisible on the tafel. The grey pills take
   the card ground on it, as on every grey card of the house. */
.abo-erste { margin-top: 0; }
.abo-plaene:not(.abo-einmalig) .abo-plan { background: var(--shade); }
.abo-plaene:not(.abo-einmalig) .abo-plan.ist-gebucht,
.abo-plaene:not(.abo-einmalig) .abo-plan.ist-gewaehlt,
.abo-plaene:not(.abo-einmalig) .abo-waehlbar:hover { border-color: var(--strong); }
.abo-plaene:not(.abo-einmalig) .plan-pille[data-plan="member"],
.abo-plaene:not(.abo-einmalig) .plan-pille[data-plan="plus"] { background: var(--card-ground); }
.abo-einmal-lead { margin: -.3rem 0 .8rem; color: var(--soft); font-size: .92rem; }
.abo-plan.abo-einmal { background: var(--card-ground); }
/* One offer per row on phone and tablet, two side by side on a desktop -
   75 rem is past the widest tablet held sideways (1194 px). With one offer on
   a desktop it takes the left half, wide enough for its sentence. */
.abo-einmalig { grid-template-columns: 1fr; }
@media (min-width: 75rem) {
  .abo-einmalig { grid-template-columns: repeat(2, 1fr); }
}
.abo-einmal-satz { margin: .2rem 0 .6rem; }
.abo-einmal-weg { margin: auto 0 0; }

/* Under the mark of the running plan: since, until, code - small and quiet. */
.abo-seit { margin: .4rem 0 0; font-size: .85rem; color: var(--soft); }
/* **A bookable card is one button over its whole face** (`.abo-plan-wahl`,
   `inset: 0`) - positioned, so it lies above the static text and takes the
   click anywhere on the card. What must stay clickable on top (the code
   link, the layer) is positioned above it. */
.abo-plan { position: relative; overflow: hidden; }
.abo-plan-wahl {
  position: absolute; inset: 0; z-index: 0; padding: 0; border: 0;
  background: none; border-radius: inherit; cursor: pointer;
}
.abo-waehlbar:hover { border-color: var(--strong); }
.abo-plan-wahl:focus-visible { outline: 2px solid var(--strong); outline-offset: -3px; }
.abo-plan.ist-gewaehlt { border-color: var(--strong); box-shadow: inset 0 0 0 1px var(--strong); }
/* **The code strip at the foot of a bookable card** - on the ground of the
   bars (`--nav`, black; light in dark mode), a soft shadow upwards, the link
   a size smaller, "Buchen" on the right once a code covers the price. It is there only on the chosen card; the
   room it takes is reserved on every bookable card (`padding-bottom`), so
   choosing changes nothing about the card's height. Opened, the field grows
   in under the link (`grid-template-rows` 0fr -> 1fr): anchored at the
   bottom, the strip and its link move up over the card. */
.abo-waehlbar { padding-bottom: 3.2rem; }
.abo-code-fuss {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 1;
  display: none; flex-direction: column;
  padding: .7rem 1.2rem; background: var(--nav); color: var(--nav-ink);
  box-shadow: 0 -3px 8px rgba(0, 0, 0, .06);
}
.abo-code-reihe { display: flex; align-items: center; justify-content: space-between; gap: .6rem; min-height: 1.4rem; }
/* On the black strip a button that turns black under the pointer vanishes -
   here it turns light grey instead. */
.abo-code-fuss .action:hover, .abo-code-fuss .action:focus-visible {
  background: var(--shade); color: var(--strong); border-color: var(--shade);
}
/* While the code is checked, a spinner lies over "Prüfen": the word goes
   transparent (the button keeps its width), a ring turns in its middle. */
.abo-code .action[data-laedt] { position: relative; color: transparent; }
.abo-code .action[data-laedt]::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 1rem; height: 1rem; margin: -.5rem 0 0 -.5rem;
  border: 2px solid var(--line); border-top-color: var(--strong); border-radius: 50%;
  animation: abo-lader .7s linear infinite;
}
@keyframes abo-lader { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .abo-code .action[data-laedt]::after { animation-duration: 2s; }
}
.abo-code-fuss .abo-code-weg { color: var(--nav-ink); }
.abo-code-fuss .abo-code-weg:focus-visible { outline-color: var(--nav-ink); }
.abo-plan .abo-code-fuss .abo-buchen { margin-top: 0; width: auto; flex: none; min-height: 2.25rem; padding: .35rem .9rem; }
.ist-gewaehlt .abo-code-fuss { display: flex; }
.abo-code-weg { align-self: flex-start; font-size: .82rem; }
.abo-code-inhalt { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .2s ease-out; }
.abo-code-inhalt > div { overflow: hidden; min-height: 0; }
.abo-code-fuss.ist-auf .abo-code-inhalt { grid-template-rows: 1fr; }
/* Padding, not margin: a margin on the form slipped out through the closed
   row and left .6 rem under the link - the link sat off centre. */
.abo-code-inhalt > div > * { padding-top: .6rem; }
.abo-code-fuss input { background: var(--paper); color: var(--strong); border-color: var(--paper); }
@media (prefers-reduced-motion: reduce) { .abo-code-inhalt { transition: none; } }
.abo-code { display: grid; gap: .35rem; }
.abo-code label { font-size: .85rem; font-weight: 600; }
.abo-code .mp-gruss-reihe input { min-width: 0; }
.abo-plan .abo-code .action { margin-top: 0; align-self: stretch; }
.abo-rechtlich { margin-top: .4rem; }

/* The entries a code is limited to - pills with their cross. */
.rabatt-eintraege { margin: .45rem 0 .2rem; }
.rabatt-eintraege:empty { display: none; }
.rabatt-pille { display: inline-flex; align-items: center; gap: .3rem; }
.rabatt-pille button {
  border: 0; background: none; padding: 0 .1rem; cursor: pointer;
  font: inherit; color: var(--soft); line-height: 1;
}
.rabatt-pille button:hover, .rabatt-pille button:focus-visible { color: var(--strong); }


/* ---------------------------------------------------------------------------
   THE BAR AT THE TOP RIGHT OF THE BACKEND
   ---------------------------------------------------------------------------

   Who is signed in: later the bell for news, and the account with its menu.
   It stands in
   the row where the bar of the shell sits outside, in its colour (`--nav`),
   as high as that row (`--navheight`) - the backend has no shell bar, so the
   corner belongs to it. */
.bk-kopfleiste {
  position: fixed; top: 0; right: 0; z-index: 26;
  display: flex; align-items: center; gap: .8rem;
  height: var(--navheight, 3.7rem); padding: 0 .5rem 0 1rem;
  background: var(--nav); color: var(--nav-ink);
}
/**
 * **On a screen the bar spans the working area and is paper, not black.**
 * It runs from the navigation column (`--bk-nav-spalte`, so it follows the
 * grip and the collapsed column) to the window edge, its signs sit on the
 * right, and a hairline separates it from what scrolls beneath. The two
 * tokens are turned on the bar itself, so the bell, the account button and
 * both menus that hang from it take the same ground - light and dark. On the
 * phone it stays the black bar.
 */
@media (min-width: 56rem) {
  .bk-kopfleiste {
    --nav: var(--paper);
    --nav-ink: var(--strong);
    /* One pixel right of the column edge: the column's hairline sits on that
       pixel (`.bk::before`), and it runs to the top of the window. */
    left: calc(var(--bk-nav-spalte, 0px) + 1px);
    justify-content: flex-end;
    border-bottom: 1px solid var(--line);
    /* The account's ground, taken here where `--shade` is still the house's:
       inside the menu the token is rewritten, and a menu cannot read the
       value it redefines. */
    --konto-grund: var(--shade);
    /* The house's hairline, taken here for the same reason: inside the two
       menus `--line` is rewritten to the bar's darker mix. */
    --kopf-linie: var(--line);
  }
  /* **Both menus look alike** - on paper, a hairline in the house's `--line`
     on three sides, the card shadow. On paper a menu needs an edge of its
     own; on the black bar the ground itself was the edge. No line on top:
     the menu hangs from the bar, and the bar's own hairline is that edge. */
  .bk-kopfleiste .bk-glocke-liste,
  .bk-kopfleiste .bk-konto-menue {
    /* The dividers inside read `--line` too - on paper that is the house's
       hairline again, not the bar's darker mix. */
    --line: var(--kopf-linie);
    border: 1px solid var(--kopf-linie); border-top: 0;
    box-shadow: var(--card-shadow);
  }
  /* The account button keeps its ground under the pointer and while open;
     the menu hangs below it like the bell's list, 22 rem wide. */
  .bk-kopfleiste .bk-konto-knopf:hover,
  .bk-kopfleiste .bk-konto-knopf:focus-visible,
  .bk-kopfleiste .bk-konto-knopf[aria-expanded="true"] {
    background: var(--konto-grund);
  }
  .bk-kopfleiste .bk-konto-menue { width: 22rem; }
  /* Theme switch and bell take the same ground under the pointer as the
     account - one hover for the three things in this bar. The red dot's ring
     reads the same variable, so it follows. */
  .bk-kopfleiste .bk-glocke:hover,
  .bk-kopfleiste .bk-glocke:focus-visible,
  .bk-kopfleiste .bk-glocke[aria-expanded="true"] {
    --glocke-grund: var(--konto-grund);
  }
}
/* **The bell: always there, a red dot when something is unread.** The dot
   sits on the bell's shoulder with a ring in the bar's colour, so it reads as
   laid on the sign, not cut into it. */
.bk-glocke {
  position: relative; display: grid; place-items: center;
  width: 2.75rem; height: 2.75rem; padding: 0;
  /* **Under a sign the hover ground is a circle** - a documented exception
     to `border-radius: 0`: the ground is a touch under the finger around one
     sign, not a box of the layout, and square it read as a hole cut into the
     bar. The account beside it is a pill - the same round ends, stretched. */
  border-radius: 50%;
  background: none; border: 0; color: var(--nav-ink); cursor: pointer;
}
.bk-glocke .nav-icon { width: 1.3rem; height: 1.3rem; }
/* The ground is a variable the dot's ring reads too: under the pointer the
   ring takes the lighter ground with it instead of standing as a dark rim.
   Mixed with `--nav` rather than transparent - the same shade on the bar,
   but a colour a ring can carry. */
.bk-glocke:hover, .bk-glocke:focus-visible, .bk-glocke[aria-expanded="true"] {
  --glocke-grund: color-mix(in srgb, var(--nav-ink) 18%, var(--nav));
  background: var(--glocke-grund);
}
.bk-glocke:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: -2px; }
.bk-glocke-punkt {
  position: absolute; top: .6rem; right: .6rem;
  width: .6rem; height: .6rem; border-radius: 50%;
  background: var(--glocke-punkt); box-shadow: 0 0 0 2px var(--glocke-grund, var(--nav));
}
.bk-glocke-punkt[hidden] { display: none; }
/* **The list: the same panel as the account menu** - square, right-aligned
   under the bar, on its ground (see below). */
.bk-glocke-liste {
  position: absolute; top: 100%; right: 0;
  width: 22rem; max-height: calc(100dvh - var(--navheight, 3.7rem) - 1rem);
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--paper); color: var(--strong);
}
.bk-glocke-liste[hidden] { display: none; }
.bk-glocke-titel {
  margin: 0; padding: .75rem 1rem .5rem;
  font-size: .72rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--soft); border-bottom: 1px solid var(--line);
}
.bk-glocke-leer { margin: 0; padding: 1rem; color: var(--soft); }
.bk-glocke-zeile {
  display: grid; gap: .2rem; padding: .75rem 1rem;
  color: var(--strong); text-decoration: none;
  border-bottom: 1px solid var(--line);
}
.bk-glocke-zeile:last-child { border-bottom: 0; }
.bk-glocke-zeile:hover, .bk-glocke-zeile:focus-visible {
  background: color-mix(in srgb, var(--strong) 7%, transparent);
}
.bk-glocke-zeile:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
.bk-glocke-satz { font-weight: 600; }
/* "neu" is a state of the machine - the monospace, and the dot's colour. */
.bk-glocke-neu { color: var(--glocke-punkt); }
.bk-glocke-fuss { font-family: var(--mono); font-size: .72rem; color: var(--soft); }

/* **The account button: portrait, first name, chevron** - at least 44 px to
   hit. The chevron turns when the menu is open: the same button closes it. */
.bk-konto-knopf {
  display: flex; align-items: center; gap: .55rem;
  min-height: 2.75rem; padding: .3rem .5rem;
  /* **A fixed width** - switching to an entry with a longer name must not
     make the button, and with it the bar, grow or shrink. What does not fit
     ends in an ellipsis; the full names stand in the title. */
  width: 15rem; flex: none;
  border-radius: 999px;
  background: none; border: 0; color: var(--nav-ink);
  font: inherit; font-weight: 600; cursor: pointer;
}
.bk-konto-knopf:hover, .bk-konto-knopf:focus-visible,
.bk-konto-knopf[aria-expanded="true"] {
  background: color-mix(in srgb, var(--nav-ink) 18%, transparent);
}
.bk-konto-knopf:focus-visible { outline: 2px solid var(--nav-ink); outline-offset: -2px; }
.bk-konto-knopf .nav-konto-bild { width: 2.2rem; height: 2.2rem; }
.bk-konto-text { flex: 1; display: grid; justify-items: start; gap: .15rem; min-width: 0; line-height: 1.15; }
.bk-konto-name { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-left: .35rem; }
/* **The chosen entry under the name** - a small monospace pill: it is a
   state of the machine (which entry the backend works on), not a word to
   read, and the house writes such states in the monospace. */
.bk-konto-pille {
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-family: var(--mono); font-size: .68rem; font-weight: 400; line-height: 1;
  padding: .25rem .75rem; border-radius: 999px;
  background: color-mix(in srgb, var(--nav-ink) 20%, var(--nav)); color: var(--nav-ink);
}
.bk-konto-knopf > .nav-icon { flex: none; width: 1.25rem; height: 1.25rem; transition: transform .15s ease; }
.bk-konto-knopf[aria-expanded="true"] > .nav-icon { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  .bk-konto-knopf > .nav-icon { transition: none; }
}

/* **The menu: square, right-aligned under the button.** It scrolls in
   itself when a keeper has many houses. */
.bk-konto-menue {
  position: absolute; top: 100%; right: 0;
  width: 19rem; max-height: calc(100dvh - var(--navheight, 3.7rem) - 1rem);
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--paper); color: var(--strong);
  padding: .3rem 0;
}
/* **Both panels hang from the bar and carry its ground** - `--nav`, black in
   light mode and turned in dark mode. The tokens are rewritten, not the
   children: the tier pills, the lines and the quiet text read `--strong`,
   `--paper`, `--soft`, `--line` and `--shade`, and on this ground they need
   the bar's two values. `--nav` itself is not redefined here, so there is no
   loop - it comes resolved from the root. */
.bk-konto-menue, .bk-glocke-liste {
  --strong: var(--nav-ink);
  --ink: var(--nav-ink);
  --paper: var(--nav);
  --soft: color-mix(in srgb, var(--nav-ink) 68%, var(--nav));
  --line: color-mix(in srgb, var(--nav-ink) 20%, var(--nav));
  --shade: color-mix(in srgb, var(--nav-ink) 14%, var(--nav));
}
/* **PLUS carries an outline only on a dark ground.** Its fill is a hint of
   `--strong` (8 %), and on a dark menu that is a shade nobody sees - the pill
   read as a word without a frame. On a light menu the fill is enough and a
   frame would be a second form for the same pill. The menu is dark on the
   phone in light mode (the black bar) and on the screen in dark mode (the
   bar there is paper, and paper is dark). The outline is drawn inside
   (`inset`), so the pill keeps its size and the line beside it does not move. */
@media (max-width: 55.99rem) {
  :root:not([data-theme="dark"]) .bk-konto-menue .plan-pille[data-plan="plus"] {
    box-shadow: inset 0 0 0 1px var(--strong);
  }
}
@media (max-width: 55.99rem) and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .bk-konto-menue .plan-pille[data-plan="plus"] { box-shadow: none; }
}
@media (min-width: 56rem) {
  :root[data-theme="dark"] .bk-konto-menue .plan-pille[data-plan="plus"] {
    box-shadow: inset 0 0 0 1px var(--strong);
  }
}
@media (min-width: 56rem) and (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .bk-konto-menue .plan-pille[data-plan="plus"] {
    box-shadow: inset 0 0 0 1px var(--strong);
  }
}
.bk-konto-menue[hidden] { display: none; }
.bk-konto-kopf {
  display: grid; gap: .2rem; padding: .75rem 1rem .85rem;
  border-bottom: 1px solid var(--line);
}
/* The address is where it comes from, not what it says - so the monospace. */
.bk-konto-adresse {
  font-family: var(--mono); font-size: .78rem; color: var(--soft);
  overflow-wrap: anywhere;
}
/* **Every line 44 px, and long names wrap** - two houses starting with
   "Gasthof …" differ at the end, so nothing is cut off. */
.bk-konto-zeile {
  display: flex; align-items: center; gap: .5rem; width: 100%;
  min-height: 2.75rem; padding: .45rem 1rem;
  background: none; border: 0; color: var(--strong);
  font: inherit; text-align: left; text-decoration: none; cursor: pointer;
}
.bk-konto-zeile:hover, .bk-konto-zeile:focus-visible {
  background: color-mix(in srgb, var(--strong) 7%, transparent);
}
.bk-konto-zeile:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
/* The tick marks the current page - a sign, not bold type. */
.bk-konto-haken { flex: none; width: 1.1rem; display: grid; place-items: center; }
.bk-konto-haken .nav-icon { width: 1.05rem; height: 1.05rem; }
.bk-konto-wort { min-width: 0; }
/* **An entry is one line** - the name takes what is left and ends in an
   ellipsis (its full name in the row's title), the tier stands at the right
   edge, so the pills of all entries form one column. */
.bk-konto-eintrag .bk-konto-wort {
  flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bk-konto-eintrag .plan-pille { flex: none; margin-left: .5rem; }
.bk-konto-abschnitt { border-top: 1px solid var(--line); padding-top: .1rem; }
.bk-konto-titel {
  margin: 0; padding: .7rem 1rem .2rem;
  font-size: .72rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--soft);
}
.bk-konto-ausgang { border-top: 1px solid var(--line); margin-top: .3rem; }

/* **On the phone the two are one bar over the whole width** - menu sign and
   mark on the left, bell and account on the right, one ground: the bar of the
   backend runs to the right edge, and this block lies on its right end. Both
   lists open over the whole width under the row. */
@media (max-width: 55.99rem) {
  .bk-leiste { right: 0; }
  .bk-kopfleiste { z-index: 32; gap: .25rem; padding: 0 .5rem 0 0; }
  .bk-glocke-liste {
    position: fixed; top: var(--navheight, 3.7rem); left: 0; right: 0; width: auto;
  }
  /* The same button as on the screen - name, chosen entry, chevron -, fixed
     at 12 rem (15 on the screen) and with less room between its parts. */
  .bk-konto-knopf { width: 12rem; gap: .35rem; padding: .3rem .35rem; }
  .bk-konto-menue {
    position: fixed; top: var(--navheight, 3.7rem); left: 0; right: 0; width: auto;
  }
  /* **On the phone the mark is the fir alone** - the signet
     (`BFPChrome.signet`, the same path in its own 24 x 32 box), not a crop of
     the word mark. Next to the menu sign it says whose backend this is; the
     word adds nothing there and takes the room bell and account need. */
  .bk-leiste .nav-logo { display: none; }
  /* Large enough to read as the mark beside the 44-px menu button, and close
     to it: the two are the left end of the bar, the account the right. */
  .bk-leiste .signet-icon { display: block; height: 2rem; width: auto; fill: var(--nav-ink); }
  .bk-leiste:has(.signet-icon) { gap: .25rem; }
  .bk-leiste .nav-brand { padding: .2rem .15rem; }
}

/* **Who, when and from which address, above a rating to review** - pills
   in the monospace, the same form as the counted numbers (`.zahl-pille`):
   they say where the rating comes from, not what it says. The address is a
   link; it darkens under the pointer. */
.pruef-herkunft { display: flex; flex-wrap: wrap; gap: .3rem; margin-top: .35rem; }
.pruef-herkunft .pruef-pille {
  display: inline-block; padding: .25rem .75rem;
  border-radius: 999px; background: var(--shade);
  font-family: var(--mono); font-size: .68rem; font-weight: 400; color: var(--soft);
  white-space: nowrap; text-decoration: none;
}
.pruef-herkunft a.pruef-pille:hover, .pruef-herkunft a.pruef-pille:focus-visible { color: var(--strong); }


/* === POLAROIDS - the way on, carried by the photo ===========================
   Built by `BFP.polaroids` (`web/item.js`), chosen by `polaroids.forPage`.

   **Stacking:** the left one lies on top, each covers the left edge of the
   next - so the credit button top right of every photo stays free.

   **Hover and focus only bring it to the very front** - no straightening,
   no lift, no zoom: the one under the pointer shows its left edge, which its
   neighbour covers otherwise. The link is the name; its `::after` covers the
   whole tilted `li`. The body lies above the `::after` but lets the pointer
   through (`pointer-events: none`), only the credit button takes it back.

   **Few:** three or four stand centred on the screen; on the phone an even
   number, so the 2 x 2 has no empty cell. */
/* **The photos lie on the footer.** The block is the last one before it, so
   the footer slides up beneath them (`--fuss-unter`) and its slant crosses the
   frames - rising to the right, it covers more of the right-hand photos. The
   block is positioned above the footer, whose `clip-path` makes it a stacking
   context at level zero. */
.polaroids { margin-block: 6rem 0; position: relative; z-index: 1; }
body:has(.polaroids) footer.foot { --fuss-unter: 9rem; }
/* From 84 rem the photos are 18 rem wide and taller - the slant moves up with them. */
@media (min-width: 84rem) {
  body:has(.polaroids) footer.foot { --fuss-unter: 12rem; }
}
/* On the phone the 2 x 2 lies deeper in the footer: the lower pair reaches
   well into the black, not just over its edge. */
@media (max-width: 48rem) {
  body:has(.polaroids) footer.foot { --fuss-unter: 9rem; }
}
html[data-mappe] body:has(.polaroids) footer.foot { --fuss-unter: 0rem; }
/* The heading stands centred in the reading column, on the axis of the row;
   the photos below keep the width of the frame. */
.polaroids > h2 { max-width: var(--text); margin-inline: auto; text-align: center; }
.polaroids-list {
  --polaroid-breite: 15rem;
  --polaroid-ueberlappung: 2.5rem;
  list-style: none; margin: 1.5rem 0 0; padding: 1rem 0 0;
  display: flex; justify-content: center;
}
.polaroid {
  /* Shrinks with the frame - five at 15 rem need 1100 px, a tablet has less. */
  position: relative; flex: 0 1 var(--polaroid-breite); min-width: 0;
  transform: rotate(var(--polaroid-tilt, 0deg));
}
.polaroid + .polaroid { margin-left: calc(-1 * var(--polaroid-ueberlappung)); }
.polaroids-list .polaroid:nth-child(1) { z-index: 5; }
.polaroids-list .polaroid:nth-child(2) { z-index: 4; }
.polaroids-list .polaroid:nth-child(3) { z-index: 3; }
.polaroids-list .polaroid:nth-child(4) { z-index: 2; }
.polaroids-list .polaroid:nth-child(5) { z-index: 1; }
/* The mouse moves nothing (it only underlines the name); the keyboard brings the focused one to the
   front, so its focus ring is not hidden behind a neighbour. As specific as
   the stacking above and after it - a plain `.polaroid:focus-within` loses. */
.polaroids-list .polaroid:focus-within { z-index: 10; }
.polaroid-body {
  position: relative; z-index: 1; pointer-events: none;
  /* Four layers, top first: a paper grain, the band across the lower margin,
     the shade of the right side, and the run from white to grey. */
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='k'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .05 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23k)'/%3E%3C/svg%3E"),
    linear-gradient(180deg, transparent 80%, var(--polaroid-band) 87%, transparent 95%),
    linear-gradient(90deg, transparent 72%, var(--polaroid-seite) 100%),
    linear-gradient(180deg, var(--polaroid-rahmen) 0%, var(--polaroid-rahmen-unten) 100%);
  box-shadow: inset 0 0 0 1px var(--polaroid-kante), var(--polaroid-schatten);
  /* A hair of rounding - photo paper, not a box of the layout (the polaroid
     exception, like the voucher's 4 px). */
  border-radius: 2px;
  padding: .7rem .7rem 0;
}
.polaroid-frame .photo { margin: 0; }
.polaroid-frame .photo::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(125deg, var(--polaroid-glanz) 0%, transparent 38%);
  box-shadow: var(--polaroid-bild-schatten);
}
.polaroid-frame .photo img { aspect-ratio: 1; object-fit: cover; }
.polaroid-frame .credit-chip { pointer-events: auto; z-index: 2; }
.polaroid-tape {
  /* On the photo, not behind it: the photo is positioned and comes later.
     Four hand-drawn tapes, rendered by `scripts/polaroid-streifen.py`; the
     aspect ratios are the ones it prints. */
  position: absolute; z-index: 3; top: -.75rem; left: 50%; width: 7.5rem;
  aspect-ratio: 3.117;
  translate: -50% 0; rotate: var(--streifen-tilt, 0deg);
  background: url("/polaroid-streifen-1.webp") center / 100% 100% no-repeat;
}
.polaroid-tape[data-streifen="2"] { aspect-ratio: 2.791; background-image: url("/polaroid-streifen-2.webp"); }
.polaroid-tape[data-streifen="3"] { aspect-ratio: 3.529; background-image: url("/polaroid-streifen-3.webp"); }
.polaroid-tape[data-streifen="4"] { aspect-ratio: 3.810; background-image: url("/polaroid-streifen-4.webp"); }
.polaroid-name {
  /* **Written on the white margin below the photo**, like the template: the
     margin is this box - a fixed height (two lines of hand), so every
     polaroid in a row has the same frame and a late font moves nothing. The
     text is centred in it; the inner span clamps to two lines. */
  display: flex; align-items: center; justify-content: center;
  height: 2.8rem; pointer-events: auto;
  /* **Centred on the polaroid, kept out of the overlap.** Both edges of a
     polaroid can lie under a neighbour, so the name keeps the overlap plus a
     small gap on both sides - the same on both, which puts it on the axis of
     the photo. The gap is .25 rem: a handwritten line wants the width of the
     margin, and the neighbour's tilted corner reaches into it only at the
     very bottom edge, below the writing. */
  width: calc(100% - 2 * (var(--polaroid-ueberlappung) + .25rem));
  margin: 0 auto; text-align: center;
  /* In hand, in ballpoint blue - the caption someone wrote on a photo. */
  color: var(--polaroid-tinte); font-family: "Caveat", var(--mono);
  font-size: 1rem; line-height: 1;
  /* No hyphens: a hand breaks between words, and "Ma-rie" reads as typesetting. */
  text-decoration: none; hyphens: manual; overflow-wrap: anywhere;
}
.polaroid-name > span {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  /* A hand runs past its letter box: Caveat's last stroke ("e", "d") reaches
     beyond the advance width, and the clamp clips at the padding edge. The
     inline padding is the room for that stroke - not on the block axis, where
     it would let a third line peek in. */
  padding-inline: .2em;
}
.polaroid-name::after { content: ""; position: absolute; inset: 0; }
/* Under the pointer only the name is underlined - nothing moves, and the
   visitor still sees that the photo is a way. */
.polaroid:hover .polaroid-name > span { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: .15em; }
.polaroid-name:focus-visible { outline: 2px solid var(--strong); outline-offset: 3px; }
/* **On the screen they lie as if put down by hand**: each a little higher or
   lower, each overlapping its neighbour by a slightly different amount
   (`--polaroid-hoch`, `--polaroid-mehr`, from the slug in `BFP.polaroids`).
   The phone keeps its tidy 2 x 2. */
@media (min-width: 64rem) {
  .polaroids-list { padding-block: 1rem .5rem; }
  .polaroid { translate: 0 var(--polaroid-hoch, 0rem); }
  .polaroid + .polaroid {
    margin-left: calc(-1 * (var(--polaroid-ueberlappung) + var(--polaroid-mehr, 0rem)));
  }
  /* The tape holds the photo, it does not stand on it: smaller, a little off
     the middle (`--streifen-versatz`), half above the edge and half on the
     frame and photo - a tape that barely reaches past the edge holds nothing.
     Black tape does not show through - a soft shadow under its
     edge lifts it off by the thickness of tape, not of a board. */
  .polaroid-tape {
    width: 6rem; top: -1rem;
    translate: calc(-50% + var(--streifen-versatz, 0rem)) 0;
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .18));
  }
}
/* The wide frame (84 rem and up) has room: larger photos, less overlap -
   five of them fill the row instead of standing in its middle. */
@media (min-width: 84rem) {
  .polaroids-list { --polaroid-breite: 18rem; --polaroid-ueberlappung: 1.5rem; }
}
@media (max-width: 64rem) {
  .polaroids-list .polaroid:nth-child(n + 5) { display: none; }
}
@media (max-width: 48rem) {
  .polaroids-list {
    display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 2rem 1.25rem;
  }
  .polaroid + .polaroid { margin-left: 0; }
  .polaroid-name { width: auto; }
  .polaroids[data-count="3"] .polaroid:nth-child(3) { display: none; }
  /* Smaller on the phone, and fixed by its lower edge: .7 rem frame plus
     .35 rem into the photo, whatever the height of the tape. */
  .polaroid-tape { width: 5.5rem; top: auto; bottom: calc(100% - 1.05rem); }
}
html[data-mappe] .polaroids { display: none; }
/* === END POLAROIDS */

/* ===========================================================================
   **`/linktree/` - the target of the link in the Instagram bio**
   ===========================================================================
   The reading column (`.about`), centred head: the portrait in a circle
   (exception 2 of `border-radius: 0`, like every portrait of the house), the
   name, one sentence. Below it the rows of `.terminliste` and the quick links
   - both existing parts; this block only spaces them. */
.linktree-kopf { text-align: center; margin-bottom: 2.5rem; }
.linktree .linktree-bild {
  display: block; width: 6rem; height: 6rem; aspect-ratio: 1; max-width: none; margin: 0 auto 1rem;
  /* A general image rule of the reading column pads images sideways - here
     that squeezed the photo into an oval inside the circle. */
  padding: 0;
  border-radius: 50%; object-fit: cover;
  /* The photo has a pale grey ground; without an edge the circle runs into
     the paper and reads as an oval. */
  box-shadow: 0 0 0 1px var(--line);
}
/* The claim is the heading - a sentence, so one step smaller than a name. */
.linktree-kopf h1 { margin: 0 auto; max-width: 24rem; font-size: clamp(1.5rem, 5vw, 2rem); line-height: 1.2; }
.linktree-neu { margin-bottom: 2.5rem; }
.linktree-neu h2,
.linktree .quick-links-titel { font-size: 1.15rem; color: var(--strong); margin: 0 0 .75rem; }

/*
 * **Woher** (`#/besucher`): Europe as one SVG. Countries in two tones only -
 * with visitors or without; the circles carry the amount. Radii and ring
 * width are set in screen pixels by the script (`sizeVisitorMap`), so only
 * colours live here. Tokens only, light and dark alike.
 */
.besucher-karte { margin: .75rem 0 0; }
.besucher-karte-flaeche { position: relative; }
.besucher-karte svg {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  max-height: 34rem;
  background: var(--paper);
  /* The map takes every gesture; the page scrolls beside it and with a plain wheel. */
  touch-action: none;
  cursor: grab;
  user-select: none;
}
.besucher-karte svg[data-dragging] { cursor: grabbing; }
.besucher-karte svg:focus-visible { outline: 2px solid var(--strong); outline-offset: 2px; }
.besucher-karte svg:focus:not(:focus-visible) { outline: none; }
@media (min-width: 40rem) {
  .besucher-karte svg { aspect-ratio: 16 / 9; }
}
/* Two square buttons in the corner, the house's square - no rounding. */
.besucher-karte-zoom {
  position: absolute;
  top: .5rem;
  right: .5rem;
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--line);
}
.besucher-karte-zoom button {
  width: 2.25rem;
  height: 2.25rem;
  border: 0;
  background: var(--paper);
  color: var(--strong);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
}
.besucher-karte-zoom button:hover { background: var(--shade); }
.besucher-karte-zoom button:focus-visible { outline: 2px solid var(--strong); outline-offset: -2px; }
@media (pointer: coarse) {
  .besucher-karte-zoom button { width: 2.75rem; height: 2.75rem; }
}
.besucher-karte path {
  fill: var(--shade);
  stroke: var(--paper);
  stroke-width: .75px;
  vector-effect: non-scaling-stroke;
}
.besucher-karte path[data-visited] { fill: color-mix(in srgb, var(--soft) 40%, var(--paper)); }
.besucher-karte circle {
  fill: var(--strong);
  fill-opacity: .8;
  stroke: var(--paper);
}
.besucher-karte circle[data-active] { fill-opacity: 1; }
/* The picked one stands out by the others stepping back, not by a new colour. */
.besucher-karte svg:has(circle[data-active]) circle:not([data-active]) { fill-opacity: .3; }
.besucher-karte-namen text {
  fill: var(--strong);
  stroke: var(--paper);
  paint-order: stroke;
  stroke-linejoin: round;
  pointer-events: none;
}
.besucher-karte figcaption { margin-top: .5rem; }
.besucher-karte-legende { margin: 0; font-size: .82rem; color: var(--soft); }
.besucher-karte-zeile { margin: .25rem 0 0; min-height: 1.5em; color: var(--strong); }
.besucher-orte-tabellen {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
  column-gap: 2rem;
}
