/* ==========================================================================
   Feste-Kalender

   Gestaltungsidee: gedrucktes Programmheft, nicht Web-App. Ein charaktervoller
   Serif-Schnitt traegt Titel und Datum, der Fliesstext laeuft in der
   System-Schrift. Farbe wird sparsam eingesetzt - Papier, Tinte, ein Akzent.
   Struktur entsteht ueber Typografie und Weissraum, nicht ueber Rahmen,
   Schatten und Verlaeufe.
   ========================================================================== */

@font-face {
  font-family: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/static/fonts/fraunces-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: 'Fraunces';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('/static/fonts/fraunces-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* Papier und Tinte. Leicht warm gebrochen - reines Weiss auf Schwarz
     flimmert und wirkt kalt. */
  --paper:        #faf7f2;
  --paper-raised: #ffffff;
  --paper-sunken: #f2eee6;
  --ink:          #1c1a17;
  --ink-soft:     #56514a;
  --ink-faint:    #8b8478;
  --rule:         #ded8cc;

  /* Ein Akzent, gedecktes Ziegelrot. Traegt Links, aktive Zustaende und das
     Datum - mehr Farbe braucht die Seite nicht. */
  --accent:       #a8432a;
  --accent-soft:  #f5e7e2;
  --accent-ink:   #ffffff;

  --ok:     #3f6b42;
  --warn:   #8a6a1f;
  --danger: #a3302b;

  /* Die Kartenkacheln kommen bunt von OpenStreetMap. Der Filter nimmt ihnen
     die Farbe und zieht sie ins Papierne - sonst saehe die Karte aus wie aus
     einer anderen Seite ausgeschnitten. */
  --map-filter: grayscale(1) sepia(.28) saturate(.75) brightness(1.04) contrast(.92);

  --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --font-text: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Eine Skala statt beliebiger Pixelwerte - haelt Abstaende konsistent. */
  --s1: 0.25rem;  --s2: 0.5rem;   --s3: 0.75rem;  --s4: 1rem;
  --s5: 1.5rem;   --s6: 2rem;     --s7: 3rem;     --s8: 4rem;

  --radius: 3px;          /* kantig, wie geschnittenes Papier */
  --radius-lg: 5px;
  --measure: 34rem;       /* angenehme Zeilenlaenge fuer Fliesstext */
  --page: 62rem;

  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --paper:        #16150f;
    --paper-raised: #1f1d16;
    --paper-sunken: #100f0b;
    --ink:          #ece7dc;
    --ink-soft:     #a9a294;
    --ink-faint:    #7a7365;
    --rule:         #332f26;
    --accent:       #e0846a;
    --accent-soft:  #2e211c;
    --accent-ink:   #16150f;
    --ok:     #7ba87e;
    --warn:   #d0aa55;
    --danger: #e08078;
    --map-filter: grayscale(1) invert(1) brightness(.78) contrast(1.08) sepia(.2);
  }
}
:root[data-theme='dark'] {
  --paper:        #16150f;
  --paper-raised: #1f1d16;
  --paper-sunken: #100f0b;
  --ink:          #ece7dc;
  --ink-soft:     #a9a294;
  --ink-faint:    #7a7365;
  --rule:         #332f26;
  --accent:       #e0846a;
  --accent-soft:  #2e211c;
  --accent-ink:   #16150f;
  --ok:     #7ba87e;
  --warn:   #d0aa55;
  --danger: #e08078;
  --map-filter: grayscale(1) invert(1) brightness(.78) contrast(1.08) sepia(.2);
}

/* --- Grundlagen ---------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  /* Fraunces ist eine optical-size-Variable: groessere Grade duerfen
     kontrastreicher und enger laufen. */
  font-variation-settings: 'opsz' 48, 'SOFT' 0, 'WONK' 0;
  letter-spacing: -0.012em;
  margin: 0 0 var(--s4);
  text-wrap: balance;
}
h1 { font-size: clamp(1.9rem, 1.35rem + 2.4vw, 3rem); }
h2 { font-size: clamp(1.4rem, 1.15rem + 1.1vw, 1.9rem); }
h3 { font-size: 1.15rem; font-variation-settings: 'opsz' 20; }

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

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
a:hover { text-decoration-thickness: 2px; }

/* Ein sichtbarer, einheitlicher Fokusring - Tastaturbedienung darf nicht
   raten muessen, wo man gerade ist. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 2px;
}

img { max-width: 100%; height: auto; display: block; }

hr {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: var(--s6) 0;
}

/* Nur fuer Screenreader */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: var(--s4); top: -4rem;
  background: var(--accent); color: var(--accent-ink);
  padding: var(--s2) var(--s4); z-index: 100;
  border-radius: var(--radius); transition: top 0.15s;
}
.skip-link:focus { top: var(--s4); }

/* --- Layout -------------------------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--page);
  margin-inline: auto;
  /* 16px Aussenabstand am Handy, damit nichts am Rand klebt */
  padding-inline: var(--s4);
}

main { padding-block: var(--s6) var(--s8); }

.prose { max-width: var(--measure); }
.prose h2 { margin-top: var(--s6); }
.prose ul, .prose ol { padding-left: var(--s5); margin: 0 0 var(--s4); }
.prose li { margin-bottom: var(--s1); }
.prose a { overflow-wrap: anywhere; }

/* --- Kopf ---------------------------------------------------------------- */

.site-head {
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
}
.site-head__inner {
  display: flex;
  align-items: baseline;
  gap: var(--s5);
  padding-block: var(--s4);
  flex-wrap: wrap;
}
.site-title {
  font-family: var(--font-display);
  font-variation-settings: 'opsz' 40, 'WONK' 1;
  font-size: 1.35rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
  margin-right: auto;
}
.site-title:hover { color: var(--accent); }

.site-nav { display: flex; gap: var(--s4); align-items: baseline; }
.site-nav a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 0.9rem;
}
.site-nav a:hover, .site-nav a[aria-current='page'] {
  color: var(--ink);
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* --- Datumsblock ---------------------------------------------------------
   Das Datum ist hier ein gestaltetes Element, kein Fliesstext: grosser Tag,
   kleiner Monat darueber. Das macht eine Liste auf einen Blick scanbar. */

.datebox {
  flex: none;
  width: 3.4rem;
  text-align: center;
  font-family: var(--font-display);
  line-height: 1;
  padding-top: 0.15rem;
}
.datebox__month {
  display: block;
  font-family: var(--font-text);
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.22rem;
}
.datebox__day {
  display: block;
  font-size: 1.85rem;
  font-weight: 600;
  font-variation-settings: 'opsz' 32;
  letter-spacing: -0.03em;
}
.datebox__weekday {
  display: block;
  font-family: var(--font-text);
  font-size: 0.65rem;
  color: var(--ink-faint);
  margin-top: 0.18rem;
}

/* --- Zeitspalte in der Tagesgruppe ---------------------------------------
   Steht an der Stelle des Datumsblocks und hat dieselbe Breite: die Titel
   bleiben in einer Flucht, ob gruppiert oder nicht. Innerhalb eines Tages ist
   die Uhrzeit das, was die Zeilen unterscheidet - das Datum stuende zehnmal
   gleich da und traegt nichts bei. */

.timebox {
  flex: none;
  width: 3.4rem;
  padding-top: 0.2rem;
  text-align: center;
  font-family: var(--font-text);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  line-height: 1.2;
  hyphens: auto;
}

/* --- Tagesgruppe --------------------------------------------------------- */

.eventday { margin-bottom: var(--s5); }

/* Klebt beim Scrollen oben an, bis der naechste Tag sie hochschiebt: in einer
   langen Liste weiss man sonst nach ein paar Zeilen nicht mehr, welcher Tag
   gerade laeuft. Das "bis zum naechsten" ergibt sich von selbst, weil jede
   Ueberschrift in ihrer eigenen <section> klebt.

   top ist NICHT 0: die Filterleiste klebt dort schon (z-index 10), eine
   Ueberschrift bei 0 verschwindet lautlos darunter und es sieht aus, als
   klebte sie gar nicht. --stick-top ist die gemessene Hoehe der Filterleiste,
   gesetzt von app.js - geraten geht nicht, weil die Leiste am Handy umbricht.
   Der Rueckfallwert deckt den ungebrochenen Fall ab, falls kein JavaScript
   laeuft. */
.eventday__head {
  position: sticky;
  top: var(--stick-top, 3.9rem);
  z-index: 2;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 var(--s3);
  margin: 0;
  padding: var(--s2) 0;
  background: var(--paper);
  border-bottom: 2px solid var(--ink);
  font-family: var(--font-display);
  font-variation-settings: 'opsz' 20;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}
.eventday__rel {
  font-family: var(--font-text);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--accent);
}
.eventday__count {
  margin-left: auto;
  font-family: var(--font-text);
  font-size: 0.8rem;
  font-weight: 400;
  color: var(--ink-faint);
}

/* Die gruppierte Liste bringt ihre Trennlinie schon in der Ueberschrift mit. */
.eventlist--inday { border-top: 0; }
.eventlist--inday > li:last-child { border-bottom: 0; }
.eventlist--inday .event-row { padding: var(--s3) 0; }

/* --- Festliste ----------------------------------------------------------- */

.eventlist {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--rule);
}
.eventlist > li { border-bottom: 1px solid var(--rule); }

.event-row {
  display: flex;
  gap: var(--s4);
  align-items: flex-start;
  padding: var(--s4) 0;
  text-decoration: none;
  color: inherit;
  /* Grosszuegige Trefferflaeche am Handy */
  min-height: 3.4rem;
}
.event-row:hover { background: var(--paper-sunken); }
.event-row:hover .event-row__title { color: var(--accent); }

.event-row__body { flex: 1; min-width: 0; }

.event-row__title {
  font-family: var(--font-display);
  font-variation-settings: 'opsz' 24;
  font-size: 1.12rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
  margin: 0 0 0.15rem;
  text-wrap: pretty;
}
.event-row__meta {
  font-size: 0.85rem;
  color: var(--ink-soft);
  display: flex;
  flex-wrap: wrap;
  gap: 0 var(--s3);
  margin: 0;
}
.event-row__meta > * { display: inline-flex; align-items: center; gap: 0.3em; }
.event-row__summary {
  font-size: 0.9rem;
  color: var(--ink-soft);
  margin: 0.3rem 0 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.event-row__thumb {
  flex: none;
  width: 4.5rem;
  height: 4.5rem;
  object-fit: cover;
  border-radius: var(--radius);
  background: var(--paper-sunken);
}
@media (max-width: 30rem) {
  .event-row__thumb { width: 3.4rem; height: 3.4rem; }
}

/* --- Marken / Chips ------------------------------------------------------ */

.tag {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0.16em 0.5em;
  border-radius: var(--radius);
  background: var(--paper-sunken);
  color: var(--ink-soft);
  white-space: nowrap;
}
.tag--cat { background: var(--cat-color, var(--paper-sunken)); color: #fff; }
.tag--cancelled { background: var(--danger); color: #fff; }
.tag--draft { background: var(--warn); color: #fff; }

/* --- Filterleiste -------------------------------------------------------- */

.filterbar {
  display: flex;
  gap: var(--s2);
  align-items: center;
  flex-wrap: wrap;
  padding-block: var(--s4);
  /* Bleibt beim Scrollen oben - am Handy der Unterschied zwischen
     "nutzbar" und "staendig hochscrollen". */
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
  margin-bottom: var(--s5);
}
.filterbar__search { flex: 1 1 12rem; min-width: 0; }

.chips {
  display: flex;
  gap: var(--s2);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 2px;
}
.chips::-webkit-scrollbar { display: none; }

.chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  min-height: 2.2rem;
  padding: 0 var(--s3);
  border: 1px solid var(--rule);
  border-radius: 100px;
  background: var(--paper-raised);
  color: var(--ink-soft);
  font-size: 0.85rem;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  /* Ein <button> erbt die Schrift nicht von selbst - geo.js baut die
     Ortsvorschlaege als Knoepfe, die wie die Filterchips aussehen sollen. */
  font-family: inherit;
}
.chip:hover { border-color: var(--ink-faint); color: var(--ink); }
.chip[aria-pressed='true'], .chip.is-active {
  background: var(--ink);
  border-color: var(--ink);
  color: var(--paper);
}

/* --- Formulare ----------------------------------------------------------- */

.field { margin-bottom: var(--s4); }
.field > label, .label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink-soft);
  margin-bottom: var(--s1);
}
.field__hint {
  font-size: 0.8rem;
  color: var(--ink-faint);
  margin: var(--s1) 0 0;
}
.field__error {
  font-size: 0.82rem;
  color: var(--danger);
  margin: var(--s1) 0 0;
}

input[type='text'], input[type='password'], input[type='search'], input[type='url'],
input[type='email'], input[type='number'], input[type='date'], input[type='time'],
input[type='datetime-local'], select, textarea {
  width: 100%;
  /* 16px verhindert, dass iOS beim Fokus hineinzoomt. */
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--paper-raised);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 0.55rem 0.7rem;
  min-height: 2.75rem;
}
textarea { min-height: 9rem; resize: vertical; line-height: 1.55; }
input:focus, select:focus, textarea:focus { border-color: var(--accent); }
input[aria-invalid='true'], select[aria-invalid='true'], textarea[aria-invalid='true'] {
  border-color: var(--danger);
}
input::placeholder, textarea::placeholder { color: var(--ink-faint); }

select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 1.05rem) 1.2rem, calc(100% - 0.7rem) 1.2rem;
  background-size: 0.35rem 0.35rem;
  background-repeat: no-repeat;
  padding-right: 2.2rem;
}

.checkline {
  display: flex;
  align-items: flex-start;
  gap: var(--s2);
  margin-bottom: var(--s3);
}
.checkline input[type='checkbox'], .checkline input[type='radio'] {
  width: 1.15rem; height: 1.15rem;
  margin: 0.24rem 0 0;
  accent-color: var(--accent);
  flex: none;
}
.checkline label { font-size: 0.95rem; color: var(--ink); font-weight: 400; }

.form-grid {
  display: grid;
  gap: 0 var(--s4);
  grid-template-columns: 1fr;
}
@media (min-width: 40rem) {
  .form-grid--2 { grid-template-columns: 1fr 1fr; }
  .form-grid .span-2 { grid-column: 1 / -1; }
}

/* --- Schaltflaechen ------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  /* 44px Mindesthoehe - Daumenbedienung */
  min-height: 2.75rem;
  padding: 0 var(--s4);
  font: inherit;
  font-size: 0.95rem;
  font-weight: 500;
  border: 1px solid var(--ink);
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--paper);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
}
.btn:hover { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn:disabled, .btn[aria-disabled='true'] { opacity: 0.5; cursor: not-allowed; }

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--rule);
}
.btn--ghost:hover { background: var(--paper-sunken); color: var(--ink); border-color: var(--ink-faint); }

.btn--danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn--danger:hover { filter: brightness(0.9); background: var(--danger); border-color: var(--danger); }

.btn--sm { min-height: 2.15rem; font-size: 0.85rem; padding: 0 var(--s3); }
.btn--block { width: 100%; }

.btn-row {
  display: flex;
  gap: var(--s3);
  flex-wrap: wrap;
  align-items: center;
}
/* In Tabellenzellen enger, damit die Spalte nicht auseinanderlaeuft. */
.btn-row--tight { gap: var(--s2); flex-wrap: nowrap; }

/* --- Meldungen ----------------------------------------------------------- */

.notice {
  padding: var(--s3) var(--s4);
  border-radius: var(--radius);
  border-left: 3px solid var(--ink-faint);
  background: var(--paper-sunken);
  margin-bottom: var(--s5);
  font-size: 0.95rem;
}
.notice--ok     { border-left-color: var(--ok);     }
.notice--warn   { border-left-color: var(--warn);   }
.notice--error  { border-left-color: var(--danger); }

/* Der Leerzustand fuellt den Bildschirm, statt als kleiner Kasten in viel Weiss
   zu haengen. Das ist nicht nur huebscher, es ist die Bedingung dafuer, dass die
   Verankerung in app.js ueberhaupt greifen kann: faellt die Seite bei einer
   Auswahl ohne Treffer auf Fensterhoehe zusammen, gibt es keinen Scrollweg mehr,
   der Browser kappt den Stand - und genau das war das Springen. Eine Seite, die
   eine Fensterhoehe hoch bleibt, laesst sich dagegen immer so weit scrollen,
   dass die Filterzeile wieder dort steht, wo der Finger sie verlassen hat. */
.empty {
  min-height: calc(100vh - 4rem);
  display: grid;
  align-content: center;
  justify-items: center;
  gap: var(--s2);
  text-align: center;
  padding: var(--s8) var(--s4);
  color: var(--ink-faint);
}
.empty h2 { font-size: 1.2rem; color: var(--ink-soft); }

/* Der Ergebnisbereich haelt eine Mindesthoehe. Sonst wird die Seite bei jedem
   Filterwechsel unterschiedlich lang, der Scrollstand passt nicht mehr dazu,
   und alles darunter rutscht unter dem Finger weg. Siehe die Verankerung in
   app.js, die den Rest ausgleicht. */
.ansicht { min-height: 70vh; }

/* --- Gefaellt mir und Kommentare ----------------------------------------- */

.interaktion {
  border-top: 1px solid var(--rule);
  padding-top: var(--s5);
}
/* Der Platzhalter haelt die Hoehe, bis der echte Bereich nachgeladen ist -
   sonst springt der Seitenfuss beim Eintreffen nach unten. */
.interaktion--platzhalter { min-height: 9rem; }

.likebar {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin-bottom: var(--s6);
}
.likebtn {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  min-height: 2.75rem;
  padding: 0 var(--s4);
  font: inherit;
  font-size: 0.92rem;
  color: var(--ink);
  background: var(--paper-raised);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  cursor: pointer;
}
.likebtn:hover { border-color: var(--accent); color: var(--accent); }
.likebtn.is-on { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); }
/* Das gefuellte Herz ueber CSS statt ueber das fill-Attribut: im cachebaren
   Ausschnitt kennt der Server den Stand nicht, und das Skript setzt dort nur
   die Klasse. Eine CSS-Regel sticht das Praesentationsattribut. */
.likebtn.is-on svg path { fill: currentColor; }

.interaktion__title { font-size: 1.1rem; margin-bottom: var(--s4); }

.comments { list-style: none; margin: 0 0 var(--s6); padding: 0; }
.comment {
  padding: var(--s4) 0;
  border-bottom: 1px solid var(--rule);
  max-width: var(--measure);
}
.comment:first-child { border-top: 1px solid var(--rule); }
.comment__meta { display: flex; gap: var(--s3); margin: 0 0 var(--s2); }
.comment__body {
  margin: 0;
  /* Kommentare sind reiner Text - Zeilenumbrueche muessen erhalten bleiben,
     weil es kein Markdown gibt, das Absaetze bilden koennte. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.commentform { max-width: var(--measure); }

/* Der Honigtopf. Bewusst nicht display:none - das erkennen die besseren Bots.
   Aus dem Sichtfeld geschoben, nicht fokussierbar, fuer Screenreader per
   aria-hidden ausgenommen. */
.honigtopf {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Das Herz in der Liste: eine Zahl ohne Wort, davor ein kleines Zeichen. */
.likes::before { content: '\2665\00a0'; }

/* --- Karten (Leaflet) ---------------------------------------------------- */

.map {
  height: 16rem;
  border-radius: var(--radius);
  border: 1px solid var(--rule);
  background: var(--paper-sunken);
  z-index: 0;   /* bleibt unter der klebenden Filterleiste */
}
@media (min-width: 45rem) { .map { height: 20rem; } }

/* Papier statt Buntheit. Der Filter liegt auf der Kachelebene, nicht auf dem
   Container - Marker und Kreis sollen ihre Farbe behalten. */
.map--paper { position: relative; }
.map--paper .leaflet-tile-pane { filter: var(--map-filter); }
/* Ein feines Korn darueber, wie bei einem gedruckten Plan. Ueber den Kacheln
   (Ebene 200), unter den Markern (600). */
.map--paper::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 450;
  pointer-events: none;
  opacity: .1;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --- Marker: Datumsstempel statt Pin ------------------------------------- */

.pin {
  position: relative;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 34px;
  line-height: 1;
  background: var(--paper-raised);
  color: var(--ink);
  border: 1px solid var(--ink);
  border-left: 3px solid var(--cat-color, var(--ink));
  border-radius: var(--radius);
  /* Der Versatz statt eines weichen Schattens - wie ein gedruckter Stempel. */
  box-shadow: 2px 2px 0 var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.pin::after {
  content: '';
  position: absolute;
  bottom: -5px;
  left: 50%;
  width: 7px;
  height: 7px;
  transform: translateX(-50%) rotate(45deg);
  background: var(--paper-raised);
  border-right: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
}
.pin__day {
  font-family: var(--font-display);
  font-size: .95rem;
  font-weight: 600;
  font-variation-settings: 'opsz' 16;
}
.pin__mon {
  font-family: var(--font-text);
  font-size: .55rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ink-soft);
  margin-top: .1rem;
}
.pin.is-active {
  background: var(--accent);
  color: var(--accent-ink);
  border-color: var(--accent);
  z-index: 1000;
}
.pin.is-active .pin__mon { color: var(--accent-ink); }
.pin.is-active::after { background: var(--accent); border-color: var(--accent); }

/* Mehrere Feste an einem Ort: zwei versetzte Papierlagen dahinter. Das liest
   sich sofort als "da ist mehr" - ohne Cluster-Bibliothek. */
.pin--stack::before {
  content: '';
  position: absolute;
  inset: 0;
  transform: translate(3px, 3px);
  background: var(--paper-sunken);
  border: 1px solid var(--ink-faint);
  border-radius: var(--radius);
  z-index: -1;
}

/* Aufgefaechert: die Striche, die jeden herausgezogenen Stempel an seinem
   tatsaechlichen Ort festhalten. Als CSS und nicht als Leaflet-Option, weil
   stroke in CSS das Praesentationsattribut des Pfades ueberschreibt - so
   stimmt die Farbe auch im dunklen Theme. */
.faecher-linie {
  stroke: var(--ink-faint);
  stroke-dasharray: 3 3;
}

/* Der Suchmittelpunkt: ein Fadenkreuz, kein weiterer Pin. */
.pin--hier {
  display: block;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 2px solid var(--accent);
  background: var(--paper-raised);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
}

/* --- Kartenansicht ------------------------------------------------------- */

.mapview { display: grid; gap: var(--s4); }
.mapview__map .map { height: 52vh; min-height: 18rem; }

@media (min-width: 60rem) {
  .mapview { grid-template-columns: 24rem 1fr; align-items: start; }
  /* Die Karte bleibt stehen, waehrend die Liste daneben laeuft. */
  .mapview__map { position: sticky; top: var(--s4); order: 2; }
  .mapview__map .map { height: calc(100vh - 13rem); }
  .mapview__list { max-height: calc(100vh - 13rem); overflow: auto; }
}
@media (max-width: 59.99rem) {
  .mapview__map { order: -1; }
}

.eventlist--compact .event-row { padding: var(--s3) 0; min-height: 0; }
.eventlist--compact .event-row__thumb { display: none; }
.eventlist--compact .event-row__summary { display: none; }
.eventlist > li.is-active { background: var(--accent-soft); }

/* --- Ansichtswechsel ----------------------------------------------------- */

.viewswitch {
  display: inline-flex;
  margin-bottom: var(--s4);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
}
.viewswitch__opt {
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: .55rem var(--s4);
  min-height: 2.5rem;
  font-size: .88rem;
  text-decoration: none;
  color: var(--ink-soft);
  background: var(--paper-raised);
  border-right: 1px solid var(--rule);
}
.viewswitch__opt:last-child { border-right: 0; }
.viewswitch__opt:hover { color: var(--accent); }
.viewswitch__opt.is-active {
  background: var(--ink);
  color: var(--paper);
}
.viewswitch__opt.is-active:hover { color: var(--paper); }

/* --- Umkreisleiste ------------------------------------------------------- */

.geobar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s2);
  margin-bottom: var(--s4);
}
.geobar__field { flex: 1 1 14rem; min-width: 0; }
.geobar input[type=text] { width: 100%; }
.geobar select { width: auto; }
.geobar__status { flex-basis: 100%; margin: 0; color: var(--ink-faint); }
.geobar__status.is-error { color: var(--danger); }

/* Die Ortsvorschlaege nach einer Fehlsuche. Leer ist der Kasten unsichtbar -
   flex-Container ohne Kinder nehmen keine Hoehe ein, es braucht also kein
   hidden, das jemand vergessen koennte umzuschalten. */
.geobar__hints {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}
/* Lange Nominatim-Namen duerfen umbrechen, sonst schiebt ein einziger Treffer
   die Leiste aus dem Bild. */
.geobar__hints .chip {
  white-space: normal;
  text-align: left;
  max-width: 100%;
  padding-top: 0.3rem;
  padding-bottom: 0.3rem;
}

.chips--sort { align-items: center; margin-bottom: var(--s5); }
.chips__label { margin-right: var(--s1); }
.chip--sm { font-size: .78rem; padding: .25rem .6rem; min-height: 0; }

/* --- Kalender ------------------------------------------------------------ */

.cal-nav {
  display: grid;
  grid-template-columns: 2.5rem 1fr 2.5rem;
  align-items: center;
  gap: var(--s3);
  margin-bottom: var(--s4);
}
.cal-nav__title {
  margin: 0;
  text-align: center;
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 600;
  font-variation-settings: 'opsz' 28;
  letter-spacing: -0.01em;
}
.cal-nav__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  color: var(--ink-soft);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised);
}
.cal-nav__arrow:hover { color: var(--accent); border-color: var(--accent); }
.cal-nav__today { margin: calc(var(--s4) * -1) 0 var(--s4); text-align: center; }

/* Hairlines ueber gap:1px auf getoentem Grund - das ergibt die duennen
   Trennlinien eines gedruckten Kalenderblatts statt Kaestchen mit Raendern. */
.cal {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
}
.cal__head {
  background: var(--paper-sunken);
  padding: var(--s3);
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
}
.cal__day {
  position: relative;
  background: var(--paper-raised);
  min-height: 8.5rem;
  padding: var(--s2) var(--s2) var(--s3);
}
/* Das Wochenende bekommt den Papierton - das gibt dem Raster seinen Rhythmus
   und macht auf einen Blick klar, wo eine Woche endet. */
.cal__day--we { background: var(--paper-sunken); }
.cal__day--out { background: var(--paper); }
.cal__day--out .cal__num { color: var(--ink-faint); opacity: .5; }
.cal__day--out .cal__ev { opacity: .5; }

.cal__num {
  display: block;
  margin-bottom: var(--s2);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  text-align: right;
}
.cal__wd { display: none; }
/* Heute: die Zahl in einem Kreis, wie im Taschenkalender angestrichen. */
.cal__day.is-today .cal__nr {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.65rem;
  height: 1.65rem;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
}

.cal__ev {
  display: block;
  margin-top: .22rem;
  padding: .16rem .3rem .16rem .4rem;
  border-left: 3px solid var(--cat-color, var(--ink-faint));
  background: var(--paper);
  font-size: .78rem;
  line-height: 1.3;
  text-decoration: none;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cal__day--we .cal__ev { background: var(--paper-raised); }
.cal__ev:hover { color: var(--accent); border-left-width: 5px; }
.cal__ev--cont { color: var(--ink-soft); font-style: italic; }
.cal__ev--cancelled { text-decoration: line-through; color: var(--ink-faint); }
.cal__time { color: var(--ink-faint); }
.cal__cont { color: var(--ink-faint); }
.cal__more { display: block; margin-top: .2rem; color: var(--ink-faint); }

/* Ab dem vierten Eintrag wird es im Kaestchen zu eng; die Zahl darunter sagt,
   dass mehr da ist. Am Handy steht in der Agenda alles. */
.cal__ev:nth-of-type(n+4) { display: none; }

/* --- Kompaktes Monatsraster (nur am Handy) ------------------------------- */

.calstrip { display: none; }

@media (max-width: 47.99rem) {
  /* Oben das Raster zur Orientierung, darunter die Agenda zum Lesen. Ein
     Raster mit Titeln waere auf einem Telefon unlesbar, eine Agenda allein
     saehe aus wie die normale Liste. */
  .calstrip {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 1px;
    margin-bottom: var(--s6);
    background: var(--rule);
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    overflow: hidden;
  }
  .calstrip__wd {
    background: var(--paper-sunken);
    padding: .3rem 0;
    text-align: center;
    font-size: .62rem;
    font-weight: 600;
    letter-spacing: .06em;
    color: var(--ink-soft);
  }
  .calstrip__day {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: .22rem;
    padding: .42rem .18rem .34rem;
    min-height: 3.4rem;
    background: var(--paper-raised);
    text-decoration: none;
    color: var(--ink-soft);
  }
  /* Derselbe Rhythmus wie im grossen Raster: das Wochenende traegt den
     Papierton, damit man die Wochen auf einen Blick abzaehlt. */
  .calstrip__day.is-we { background: var(--paper-sunken); }
  .calstrip__day.is-out { color: var(--ink-faint); opacity: .45; }
  /* Ein Tag mit Festen soll sich schon vor dem Lesen abheben. */
  .calstrip__day.is-full { color: var(--ink); font-weight: 700; }
  .calstrip__num {
    font-family: var(--font-display);
    font-size: .88rem;
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
  }
  .calstrip__day.is-today .calstrip__num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.35rem;
    height: 1.35rem;
    border-radius: 50%;
    background: var(--accent);
    color: var(--accent-ink);
  }
  /* Balken statt Punkte: sie nehmen die ganze Zellenbreite ein und sind
     dadurch auch bei 50 px Spaltenbreite noch zu sehen. Ein Fest = ein
     durchgehender Balken, zwei Feste = zwei halbe, und so weiter. */
  .calstrip__bars {
    display: flex;
    gap: 2px;
    width: 100%;
    margin-top: auto;
  }
  .calstrip__bar {
    flex: 1 1 0;
    min-width: 0;
    height: 5px;
    border-radius: 2px;
    background: var(--cat-color, var(--ink-soft));
  }
  /* Ab dem vierten wird jeder Balken zum Strich; die Zahl in der Ecke sagt,
     wie viele noch fehlen. */
  .calstrip__bar:nth-child(n+4) { display: none; }
  .calstrip__plus {
    position: absolute;
    top: .12rem;
    right: .2rem;
    font-size: .55rem;
    font-weight: 700;
    line-height: 1;
    color: var(--ink-faint);
  }

  /* Das grosse Raster wird zur Agenda: nur die Tage, an denen etwas ist. */
  .cal {
    display: block;
    background: none;
    border: 0;
    border-radius: 0;
    border-top: 1px solid var(--rule);
  }
  .cal__head { display: none; }
  .cal__day { display: none; }
  .cal__day--out { display: none; }
  .cal__day--has {
    display: grid;
    grid-template-columns: 3.2rem 1fr;
    gap: var(--s3);
    align-items: start;
    min-height: 0;
    padding: var(--s4) 0;
    border-bottom: 1px solid var(--rule);
    background: none;
  }
  /* Beim Sprung aus dem Kompaktraster soll der Tag nicht unter der klebenden
     Filterleiste landen. */
  .cal__day--has { scroll-margin-top: 4.5rem; }
  .cal__num {
    margin: 0;
    text-align: center;
    font-size: 1.7rem;
    color: var(--ink);
    line-height: 1.05;
  }
  .cal__wd {
    display: block;
    font-family: var(--font-text);
    font-size: .62rem;
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: .15rem;
  }
  .cal__day.is-today .cal__nr {
    min-width: 1.9rem;
    height: 1.9rem;
  }
  /* In der Agenda ist jede Zeile ein Ziel fuer einen Daumen, kein Textschnipsel:
     mindestens 2.75rem hoch und mit Luft an den Seiten. */
  .cal__ev {
    display: flex;
    align-items: center;
    min-height: 2.75rem;
    white-space: normal;
    font-size: .95rem;
    padding: .45rem .5rem .45rem .6rem;
    margin-top: 0;
    border-left-width: 4px;
    border-radius: 0 var(--radius) var(--radius) 0;
    background: var(--paper-sunken);
  }
  .cal__ev + .cal__ev { margin-top: .35rem; }
  .cal__ev:nth-of-type(n+4) { display: block; }
  .cal__more { display: none; }
}

/* --- Tabellen (Admin) ---------------------------------------------------- */

.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.92rem;
}
table.data th, table.data td {
  text-align: left;
  padding: var(--s3) var(--s3);
  border-bottom: 1px solid var(--rule);
  vertical-align: middle;
}
table.data th {
  font-size: 0.72rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 600;
  border-bottom-width: 1px;
  white-space: nowrap;
}
table.data tbody tr:hover { background: var(--paper-sunken); }
table.data td.num { text-align: right; font-variant-numeric: tabular-nums; }

code, kbd, samp, pre { font-family: var(--font-mono); font-size: 0.88em; }
code {
  background: var(--paper-sunken);
  padding: 0.1em 0.35em;
  border-radius: var(--radius);
  overflow-wrap: anywhere;
}
pre {
  background: var(--paper-sunken);
  padding: var(--s4);
  border-radius: var(--radius);
  overflow-x: auto;
  border: 1px solid var(--rule);
}
pre code { background: none; padding: 0; }

/* --- Hilfsklassen -------------------------------------------------------- */

.stack > * + * { margin-top: var(--s4); }
.stack-sm > * + * { margin-top: var(--s2); }
.stack-lg > * + * { margin-top: var(--s6); }

.muted  { color: var(--ink-soft); }
.faint  { color: var(--ink-faint); }
.small  { font-size: 0.85rem; }
.nowrap { white-space: nowrap; }
.tnum   { font-variant-numeric: tabular-nums; }

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

/* --- Fuss ---------------------------------------------------------------- */

.site-foot {
  border-top: 1px solid var(--rule);
  padding-block: var(--s5);
  margin-top: var(--s8);
  font-size: 0.85rem;
  color: var(--ink-faint);
}
.site-foot a { color: var(--ink-soft); }

/* --- Seitenwechsel -------------------------------------------------------
   Progressive Enhancement: wo der Browser es kann, blenden Seiten sanft
   ineinander. Ohne Unterstuetzung passiert schlicht nichts. */
@view-transition { navigation: auto; }

/* ==========================================================================
   Verwaltung
   ========================================================================== */

.adminnav {
  display: flex;
  align-items: center;
  gap: var(--s4);
  flex-wrap: wrap;
  padding-block: var(--s3);
  margin-bottom: var(--s6);
  border-bottom: 1px solid var(--rule);
  font-size: 0.9rem;
}
.adminnav a {
  color: var(--ink-soft);
  text-decoration: none;
  white-space: nowrap;
}
.adminnav a:hover { color: var(--ink); }
.adminnav a[aria-current='page'] {
  color: var(--ink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 0.35em;
  text-decoration-thickness: 2px;
  text-decoration-color: var(--accent);
}
.adminnav__spacer { flex: 1 1 auto; }

/* Ein Knopf, der wie ein Link aussieht - fuer Aktionen, die ein Formular
   brauchen (Abmelden), aber wie Navigation wirken sollen. */
.linkbtn {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-size: 0.9rem;
  color: var(--ink-soft);
  cursor: pointer;
  text-decoration: none;
}
.linkbtn:hover { color: var(--accent); text-decoration: underline; }

.loginbox {
  max-width: 24rem;
  margin-inline: auto;
  padding-block: var(--s6);
}
.loginbox h1 { font-size: 1.6rem; }

fieldset.card {
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  background: var(--paper-raised);
  padding: var(--s5);
  margin: 0;
}
fieldset.card > legend {
  font-family: var(--font-display);
  font-variation-settings: 'opsz' 20;
  font-size: 1.05rem;
  font-weight: 600;
  padding-inline: var(--s2);
  margin-left: calc(var(--s2) * -1);
}
form.card {
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  background: var(--paper-raised);
  padding: var(--s5);
}

.statgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: var(--s4);
}
.stat {
  border: 1px solid var(--rule);
  border-radius: var(--radius-lg);
  background: var(--paper-raised);
  padding: var(--s4);
}
.stat__num {
  display: block;
  font-family: var(--font-display);
  font-variation-settings: 'opsz' 36;
  font-size: 2rem;
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.03em;
}
.stat__label {
  display: block;
  font-size: 0.8rem;
  color: var(--ink-faint);
  margin-top: var(--s1);
}

input[type='file'] {
  width: 100%;
  font: inherit;
  font-size: 0.9rem;
  padding: var(--s3);
  border: 1px dashed var(--rule);
  border-radius: var(--radius);
  background: var(--paper-sunken);
}
input[type='file']::file-selector-button {
  font: inherit;
  font-size: 0.85rem;
  margin-right: var(--s3);
  padding: 0.4rem var(--s3);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--paper-raised);
  color: var(--ink);
  cursor: pointer;
}

/* Die Karte im Formular darf etwas flacher sein als auf der Detailseite. */
#pickmap { height: 13rem; margin-top: var(--s3); cursor: crosshair; }

/* --- Umschalter fuers Farbschema -----------------------------------------
   Gezeigt wird, wohin der Klick fuehrt: bei hellem Design der Mond, bei
   dunklem die Sonne. Die Auswahl passiert in CSS und nicht in JavaScript,
   damit das Symbol schon beim ersten Zeichnen stimmt. */

.themetoggle { padding-inline: var(--s3); }
.themetoggle__sun { display: none; }
.themetoggle__moon { display: block; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .themetoggle__sun  { display: block; }
  :root:not([data-theme='light']) .themetoggle__moon { display: none; }
}
:root[data-theme='dark'] .themetoggle__sun  { display: block; }
:root[data-theme='dark'] .themetoggle__moon { display: none; }
:root[data-theme='light'] .themetoggle__sun  { display: none; }
:root[data-theme='light'] .themetoggle__moon { display: block; }
